diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard
index 997aa212..df6828e1 100644
--- a/VoidLink/Base.lproj/iPad.storyboard
+++ b/VoidLink/Base.lproj/iPad.storyboard
@@ -1403,16 +1403,16 @@
-
+
-
+
@@ -1578,7 +1578,7 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1661,6 +1721,8 @@
+
+
@@ -1694,6 +1756,8 @@
+
+
@@ -1717,6 +1781,8 @@
+
+
@@ -1769,7 +1835,7 @@
-
+
@@ -1803,7 +1869,7 @@
-
+
diff --git a/VoidLink/Base.lproj/iPhone.storyboard b/VoidLink/Base.lproj/iPhone.storyboard
index 4eafeb8e..283e198c 100644
--- a/VoidLink/Base.lproj/iPhone.storyboard
+++ b/VoidLink/Base.lproj/iPhone.storyboard
@@ -2284,16 +2284,16 @@
-
+
-
+
@@ -2470,6 +2470,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2494,6 +2554,8 @@
+
+
@@ -2528,6 +2590,8 @@
+
+
@@ -2550,6 +2614,8 @@
+
+
@@ -2601,7 +2667,7 @@
-
+
@@ -2640,19 +2706,19 @@
-
+
-
+
-
+
-
+
diff --git a/VoidLink/Database/DataManager.h b/VoidLink/Database/DataManager.h
index ea182d49..8e9357dc 100644
--- a/VoidLink/Database/DataManager.h
+++ b/VoidLink/Database/DataManager.h
@@ -133,6 +133,10 @@ typedef NS_ENUM(NSInteger, WidgetSizeTransition) {
enablePinch:(BOOL)enablePinch
scrollSensitivity:(CGFloat)scrollSensitivity
pinchSensitivity:(CGFloat)pinchSensitivity
+ ctrlDownForPinch:(BOOL)ctrlDownForPinch
+ leftClickDelayMs:(CGFloat)leftClickDelayMs
+ settingsMenuOffset:(CGFloat)settingsMenuOffset
+ passthroughGestures:(BOOL)passthroughGestures
backgroundSessionTimer:(NSInteger)backgroundSessionTimer;
- (NSArray*) getHosts;
diff --git a/VoidLink/Database/DataManager.m b/VoidLink/Database/DataManager.m
index a0e2d436..d66a713f 100644
--- a/VoidLink/Database/DataManager.m
+++ b/VoidLink/Database/DataManager.m
@@ -116,6 +116,10 @@
enablePinch:(BOOL)enablePinch
scrollSensitivity:(CGFloat)scrollSensitivity
pinchSensitivity:(CGFloat)pinchSensitivity
+ ctrlDownForPinch:(BOOL)ctrlDownForPinch
+ leftClickDelayMs:(CGFloat)leftClickDelayMs
+ settingsMenuOffset:(CGFloat)settingsMenuOffset
+ passthroughGestures:(BOOL)passthroughGestures
backgroundSessionTimer:(NSInteger)backgroundSessionTimer{
[_managedObjectContext performBlockAndWait:^{
@@ -182,6 +186,10 @@
settingsToSave.enablePinch = enablePinch;
settingsToSave.scrollSensitivity = [NSNumber numberWithFloat:scrollSensitivity];
settingsToSave.pinchSensitivity = [NSNumber numberWithFloat:pinchSensitivity];
+ settingsToSave.ctrlDownForPinch = ctrlDownForPinch;
+ settingsToSave.leftClickDelayMs = [NSNumber numberWithFloat:leftClickDelayMs];
+ settingsToSave.settingsMenuOffset = [NSNumber numberWithFloat:settingsMenuOffset];
+ settingsToSave.passthroughGestures = passthroughGestures;
settingsToSave.rememberFoldState = rememberFoldState;
[self saveData];
}];
diff --git a/VoidLink/Database/TemporarySettings.h b/VoidLink/Database/TemporarySettings.h
index 44ee605d..5cb31203 100644
--- a/VoidLink/Database/TemporarySettings.h
+++ b/VoidLink/Database/TemporarySettings.h
@@ -87,10 +87,14 @@
@property (nonatomic) BOOL duckOtherApps;
@property (nonatomic) BOOL muteInBackground;
@property (nonatomic) BOOL enablePinch;
+@property (nonatomic) BOOL ctrlDownForPinch;
+@property (nonatomic) BOOL passthroughGestures;
@property (nonatomic, retain) NSNumber * framePacingMode;
@property (nonatomic, retain) NSNumber * scrollSensitivity;
@property (nonatomic, retain) NSNumber * pinchSensitivity;
@property (nonatomic, retain) NSNumber * relativeTouchSlideThreshold;
+@property (nonatomic, retain) NSNumber * leftClickDelayMs;
+@property (nonatomic, retain) NSNumber * settingsMenuOffset;
- (id) initFromSettings:(Settings*)settings;
diff --git a/VoidLink/Database/TemporarySettings.m b/VoidLink/Database/TemporarySettings.m
index 151792a1..b177e540 100644
--- a/VoidLink/Database/TemporarySettings.m
+++ b/VoidLink/Database/TemporarySettings.m
@@ -147,6 +147,10 @@
self.enablePinch = settings.enablePinch;
self.scrollSensitivity = settings.scrollSensitivity;
self.pinchSensitivity = settings.pinchSensitivity;
+ self.leftClickDelayMs = settings.leftClickDelayMs;
+ self.ctrlDownForPinch = settings.ctrlDownForPinch;
+ self.settingsMenuOffset = settings.settingsMenuOffset;
+ self.passthroughGestures = settings.passthroughGestures;
#endif
return self;
diff --git a/VoidLink/Input/AbsoluteTouchHandler.m b/VoidLink/Input/AbsoluteTouchHandler.m
index 475c5dc6..3d6896d9 100644
--- a/VoidLink/Input/AbsoluteTouchHandler.m
+++ b/VoidLink/Input/AbsoluteTouchHandler.m
@@ -29,6 +29,9 @@
@implementation AbsoluteTouchHandler {
StreamView* streamView;
+ bool multiTouchesDetected;
+ bool passthroughGestures;
+
NSTimer* longPressTimer;
UITouch* lastTouchDown;
CGPoint lastTouchDownLocation;
@@ -50,6 +53,8 @@
CGFloat _edgeTolerance;
bool _delayMouseLeftClick;
+ NSTimeInterval leftClickDelay;
+
bool dragButtonDown;
UInt8 currentTouchesCount;
@@ -60,10 +65,13 @@
self = [self init];
self->streamView = view;
- // _delayMouseLeftClick = settings.delayLeftClick;
- _delayMouseLeftClick = true; // deprecate legacy absolute touch
+ multiTouchesDetected = false;
+ passthroughGestures = settings.passthroughGestures;
+
+ _delayMouseLeftClick = settings.delayLeftClick;
+ // _delayMouseLeftClick = true;
dragButtonDown = false;
-
+
leftClickTimeThreshold = 0.1;
// upper screen check
@@ -74,6 +82,8 @@
_mouseButtonForCursorMove = BUTTON_LEFT;
+ leftClickDelay = ((CGFloat)settings.leftClickDelayMs.intValue)/1000;
+
return self;
}
@@ -97,6 +107,10 @@
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
rightButtonClicked = false;
+
+
+ if([UITouchUtil touchesIn:streamView from:event].count>=2) multiTouchesDetected = true;
+
CGPoint initialPoint = [[touches anyObject] locationInView:streamView];
if(initialPoint.y < slideGestureVerticalThreshold && (initialPoint.x < _edgeTolerance || initialPoint.x > screenWidthWithThreshold)) {
@@ -126,7 +140,6 @@
// Press the left button down
if(!_delayMouseLeftClick){
- // _delayMouseLeftClick will always be true.
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); //deprecated
}
@@ -169,10 +182,10 @@
if(currentTouchesCount == 2){
if(_mouseButtonForCursorMove!=BUTTON_LEFT) LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, _mouseButtonForCursorMove);
- [TouchPadGestureHandler handleGestureIn:streamView with:event];
+ if(passthroughGestures) [TouchPadGestureHandler handleGestureIn:streamView with:event];
}
- if(currentTouchesCount>=2) return;
+ if(multiTouchesDetected) return;
if(![currentTouches containsObject:capturedTouch]) return;
@@ -197,8 +210,17 @@
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ if(TouchPadGestureHandler.ctrlDown) LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[@"CTRL"].shortValue,KEY_ACTION_UP,0);
+
if(touchPointSpawnedAtUpperScreenEdge) return; // we're done here. this touch event will not be sent to the remote PC.
+ if(multiTouchesDetected) {
+ if([UITouchUtil touchesIn:streamView from:event].count == touches.count) multiTouchesDetected = false;
+ return;
+ };
+
+ if([UITouchUtil touchesIn:streamView from:event].count == touches.count) multiTouchesDetected = false;
+
// Only fire this logic if all touches have ended
if ([touches containsObject:capturedTouch]) {
// Cancel the long press timer
@@ -220,17 +242,14 @@
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
}
- else{ // deprecated
- /*
+ else{
// Left button up on finger up
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
// Raise right button too in case we triggered a long press gesture
- LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); */
+ LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
-
- if(TouchPadGestureHandler.ctrlDown) LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[@"CTRL"].shortValue,KEY_ACTION_UP,0);
-
+
lastTouchUp = [touches anyObject];
lastTouchUpLocation = [lastTouchUp locationInView:streamView];
@@ -244,7 +263,7 @@
}
- (void)sendShortMouseLeftButtonClickEvent{
- dispatch_time_t delayShort = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC));
+ dispatch_time_t delayShort = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(leftClickDelay * NSEC_PER_SEC));
dispatch_time_t delayLong = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.03 * NSEC_PER_SEC));
dispatch_after(delayShort, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
diff --git a/VoidLink/Input/RelativeTouchHandler.m b/VoidLink/Input/RelativeTouchHandler.m
index 97fd4e13..68ee3cf7 100644
--- a/VoidLink/Input/RelativeTouchHandler.m
+++ b/VoidLink/Input/RelativeTouchHandler.m
@@ -1,6 +1,6 @@
//
// RelativeTouchHandler.m
-// Moonlight
+// VoidLink
//
// Completely refactored by True砖家 on 2024.9.13
// Copyright © 2024 True砖家 on Bilibili. All rights reserved.
@@ -33,6 +33,8 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
UITouch* touchLockedForMouseMove;
UITouch* quickTapTouch;
+ bool multiTouchesDetected;
+
CADisplayLink *displayLink;
#if TARGET_OS_TV
@@ -129,7 +131,12 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
}
touchPointSpawnedAtUpperScreenEdge = false; // reset this flag immediately if we get a touch event passing the check above, this fixes irresponsive touch after closing the command tool menu.
-
+
+ if([UITouchUtil touchesIn:streamView from:event].count>=2){
+ multiTouchesDetected = true;
+ return;
+ }
+
UITouch* candidateTouch = nil;
// the onscreen controllers are implmented by CALayer, which can not intercept UITouch event, touch will penetrate to the streamView level and captured in the touches callback of this touchHandler class.
@@ -166,11 +173,10 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet* currentTouches = [UITouchUtil touchesIn:streamView from:event];
- uint8_t currentTouchesCount = currentTouches.count;
if(![self isOnScreenControllerBeingPressed:currentTouches]) [TouchPadGestureHandler handleGestureIn:streamView with:event];
- if(currentTouchesCount>=2) return;
+ if(multiTouchesDetected) return;
if([touches containsObject:touchLockedForMouseMove]){
CGPoint currentLocation = [touchLockedForMouseMove locationInView:streamView];
@@ -184,6 +190,15 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ if(TouchPadGestureHandler.ctrlDown) LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[@"CTRL"].shortValue,KEY_ACTION_UP,0);
+
+ if(multiTouchesDetected){
+ if([UITouchUtil touchesIn:streamView from:event].count == touches.count) multiTouchesDetected = false;
+ return;
+ }
+
+ if([UITouchUtil touchesIn:streamView from:event].count == touches.count) multiTouchesDetected = false;
+
if([touches containsObject:touchLockedForMouseMove]){
// dealing with a single first tap, whether the button will be released, is going to be decided in sendLongMouseLeftButtonClickEvent
if(!mousePointerMoved && !self->quickTapDetected) [self sendLongMouseLeftButtonClickEvent];
@@ -202,14 +217,12 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2;
for(UITouch* touch in touches){
[OnScreenControls.touchesCapturedByOnScreenControls removeObject:touch];
}
-
- if(TouchPadGestureHandler.ctrlDown) LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[@"CTRL"].shortValue,KEY_ACTION_UP,0);
-
+
if([UITouchUtil touchesIn:streamView from:event].count == [touches count]){
touchLockedForMouseMove = nil;
mousePointerMoved = false; // need to reset this anyway
}
-
+
touchPointSpawnedAtUpperScreenEdge = false;
}
diff --git a/VoidLink/Input/TouchPadGestureHandler.swift b/VoidLink/Input/TouchPadGestureHandler.swift
index eafa5d38..f0061ce8 100644
--- a/VoidLink/Input/TouchPadGestureHandler.swift
+++ b/VoidLink/Input/TouchPadGestureHandler.swift
@@ -12,6 +12,7 @@ import UIKit
@objc public static var ctrlDown:Bool = false
@objc public static var enablePinch:Bool = true
+ @objc public static var ctrlDownForPinch:Bool = true
@objc public static var enableHorizontalScroll:Bool = true
@objc public static var scrollSensitivity:CGFloat = 1.0
@objc public static var pinchSensitivity:CGFloat = 1.0
@@ -36,7 +37,8 @@ import UIKit
LiSendHighResScrollEvent(Int16(pinchDelta + midPointDeltaY*5*scrollSensitivity))
if enableHorizontalScroll {LiSendHighResHScrollEvent(Int16(-midPointDeltaX*5*scrollSensitivity))}
- if !enablePinch {return};
+ if !enablePinch || !ctrlDownForPinch {return};
+
if abs(currentDistance - previousDistance) > abs(midPointDeltaY) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings["CTRL"]!, CChar(KEY_ACTION_DOWN), 0)
ctrlDown = true
diff --git a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents
index 74d5d497..c2253de9 100644
--- a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents
+++ b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents
@@ -1,5 +1,5 @@
-
+
@@ -29,6 +29,7 @@
+
@@ -52,6 +53,7 @@
+
@@ -62,6 +64,7 @@
+
@@ -75,6 +78,7 @@
+
diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings
index e1f0a37e..4e375a2b 100644
--- a/VoidLink/Localization/Localizable.xcstrings
+++ b/VoidLink/Localization/Localizable.xcstrings
@@ -1422,6 +1422,35 @@
}
}
},
+ "ctrlDownForPinchStackTip" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "When disabled, pinch gesture equals vertical scrolling. Works for some games that use vertical scrolling for zooming."
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "关闭此选项时, 捏合缩手势相当于垂直滚动. 对一些使用垂直滚动缩放画面的游戏有效."
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "關閉此選項時, 捏合縮手勢相當於垂直滾動. 對一些使用垂直滾動縮放畫面的遊戲有效."
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "關閉此選項時, 捏合縮手勢相當於垂直滾動. 對一些使用垂直滾動縮放畫面的遊戲有效."
+ }
+ }
+ }
+ },
"Current profile updated successfully" : {
"extractionState" : "manual",
"localizations" : {
diff --git a/VoidLink/MenuSectionView.m b/VoidLink/MenuSectionView.m
index 1e73f3e9..40e4c1f5 100644
--- a/VoidLink/MenuSectionView.m
+++ b/VoidLink/MenuSectionView.m
@@ -58,7 +58,7 @@ static BOOL overridePersistedFoldState = YES;
_isExpanded = YES;
_expandable = true;
_backgroundColor = [UIColor clearColor];
- _rootStackViewSpacing = [self isIPhone] ? 10 : 13.8;
+ _rootStackViewSpacing = [self isIPhone] ? 10 : 12;
_subStackViews = [NSMutableArray array];
_headerViewHeight = 37;
_headerViewVerticalSpacing = 25;
@@ -342,7 +342,9 @@ static BOOL overridePersistedFoldState = YES;
- (void)updateViewForFoldState {
- [self setupConstraints];
+ // [self setupConstraints];
+ // don't run this repeatedly
+
NSInteger visibleCount = 0;
for (UIView *subview in _rootStackView.arrangedSubviews) {
if (!subview.isHidden) {
diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m
index cbd1d7e6..8e9c17a0 100644
--- a/VoidLink/ViewControllers/MainFrameViewController.m
+++ b/VoidLink/ViewControllers/MainFrameViewController.m
@@ -1183,7 +1183,7 @@ static NSMutableSet* hostList;
// [settingsViewController widget:settingsViewController.bitrateSlider setEnabled:!self.settingsExpandedInStreamView];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.optimizeGamesStack];
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.audioOnPcStack];
- [settingsViewController.touchModeSelector setEnabled:!_settingsExpandedInStreamView || !_sessionLaunchedWithAbsoluteTouch];
+ [settingsViewController.touchModeSelector1 setEnabled:!_settingsExpandedInStreamView || !_sessionLaunchedWithAbsoluteTouch];
[settingsViewController.codecSelector setEnabled:!_settingsExpandedInStreamView];
[settingsViewController.yuv444Switch setEnabled:!_settingsExpandedInStreamView];
[settingsViewController.hdrSwitch setEnabled:!_settingsExpandedInStreamView && [settingsViewController hdrSupported]];
diff --git a/VoidLink/ViewControllers/SettingsViewController.h b/VoidLink/ViewControllers/SettingsViewController.h
index 35b77cf4..3a3805fd 100644
--- a/VoidLink/ViewControllers/SettingsViewController.h
+++ b/VoidLink/ViewControllers/SettingsViewController.h
@@ -68,7 +68,7 @@
@property (strong, nonatomic) IBOutlet UISegmentedControl *resolutionSelector;
@property (strong, nonatomic) IBOutlet UISwitch *customResolutionSwitch;
@property (strong, nonatomic) IBOutlet UILabel *touchModeLabel;
-@property (strong, nonatomic) IBOutlet UISegmentedControl *touchModeSelector;
+@property (strong, nonatomic) IBOutlet UISegmentedControl *touchModeSelector1;
@property (strong, nonatomic) IBOutlet UISwitch *enableOswForNativeTouchSwitch;
@property (strong, nonatomic) IBOutlet UILabel *onscreenControllerLabel;
@property (strong, nonatomic) IBOutlet UISegmentedControl *onScreenWidgetSelector;
@@ -205,6 +205,14 @@
@property (strong, nonatomic) IBOutlet UIStackView *touchModeStack2;
@property (strong, nonatomic) IBOutlet UISegmentedControl *touchModeSelector2;
+@property (strong, nonatomic) IBOutlet UIStackView *ctrlDownForPinchStack;
+@property (strong, nonatomic) IBOutlet UISwitch *ctrlDownForPinchSwitch;
+
+@property (strong, nonatomic) IBOutlet UIStackView *leftClickDelayStack;
+@property (strong, nonatomic) IBOutlet UISlider *leftClickDelaySlider;
+
+@property (strong, nonatomic) IBOutlet UIStackView *passthroughGesturesStack;
+@property (strong, nonatomic) IBOutlet UISwitch *passthroughGesturesSwitch;
@property (strong, nonatomic) IBOutlet UIStackView *testStack;
diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m
index aa63206c..7f995d40 100644
--- a/VoidLink/ViewControllers/SettingsViewController.m
+++ b/VoidLink/ViewControllers/SettingsViewController.m
@@ -460,7 +460,9 @@ BOOL isCustomResolution(int resolutionSelected) {
//CGSize currentResolution = CGSizeMake(currentSettings.width.intValue, currentSettings.height.intValue);
[self.customResolutionSwitch setOn: isCustomResolution(self->tempSettings.resolutionSelected.intValue)];
[self.resolutionSelector setEnabled:!self.customResolutionSwitch.isOn];
- [self touchModeChanged:self.touchModeSelector]; // a special fix for iOS 14 to set hidden for the "enableOswStack"
+ [self touchModeChanged:self.touchModeSelector1]; // a special fix for iOS 14 to set hidden for the "enableOswStack"
+
+ _scrollView.contentOffset = CGPointMake(_scrollView.contentOffset.x, tempSettings.settingsMenuOffset.floatValue);
settingsViewJustExpanded = false;
}
@@ -712,14 +714,16 @@ BOOL isCustomResolution(int resolutionSelected) {
[touchAndControlSection setSectionWithIcon:[UIImage imageNamed:@"arcade.stick.console"] andSize:20.5];
}
[self addSetting:self.touchModeStack ofId:@"touchModeStack" withInfoTag:YES withDynamicLabel:NO to:touchAndControlSection];
+ [self addSetting:self.mousePointerVelocityStack ofId:@"mousePointerVelocityStack" withInfoTag:NO withDynamicLabel:YES to:touchAndControlSection];
[self addSetting:self.pointerVelocityDividerStack ofId:@"pointerVelocityDividerStack" withInfoTag:YES withDynamicLabel:YES to:touchAndControlSection];
[self addSetting:self.pointerVelocityFactorStack ofId:@"pointerVelocityFactorStack" withInfoTag:YES withDynamicLabel:YES to:touchAndControlSection];
+ [self addSetting:self.delayLeftClickStack ofId:@"delayLeftClickStack" withInfoTag:YES withDynamicLabel:NO to:touchAndControlSection];
+ [self addSetting:self.passthroughGesturesStack ofId:@"passthroughGesturesStack" withInfoTag:NO withDynamicLabel:NO to:touchAndControlSection];
[self addSetting:self.pinchGestureStack ofId:@"pinchGestureStack" withInfoTag:NO withDynamicLabel:NO to:touchAndControlSection];
- [self addSetting:self.mousePointerVelocityStack ofId:@"mousePointerVelocityStack" withInfoTag:NO withDynamicLabel:YES to:touchAndControlSection];
+ [self addSetting:self.ctrlDownForPinchStack ofId:@"ctrlDownForPinchStack" withInfoTag:YES withDynamicLabel:NO to:touchAndControlSection];
[self addSetting:self.scrollSensitivityStack ofId:@"scrollSensitivityStack" withInfoTag:NO withDynamicLabel:YES to:touchAndControlSection];
[self addSetting:self.pinchSensitivityStack ofId:@"pinchSensitivityStack" withInfoTag:NO withDynamicLabel:YES to:touchAndControlSection];
[self addSetting:self.mousePointerVelocityStack ofId:@"mousePointerVelocityStack" withInfoTag:NO withDynamicLabel:YES to:touchAndControlSection];
- // [self addSetting:self.delayLeftClickStack ofId:@"delayLeftClickStack" withInfoTag:YES withDynamicLabel:NO to:touchAndControlSection];
[self addSetting:self.onScreenWidgetStack ofId:@"onScreenWidgetStack" withInfoTag:YES withDynamicLabel:YES to:touchAndControlSection];
[self addSetting:self.buttonVisualFeedbackStack ofId:@"buttonVisualFeedbackStack" withInfoTag:NO withDynamicLabel:NO to:touchAndControlSection];
[self addSetting:self.swapAbxyStack ofId:@"swapAbaxyStack" withInfoTag:NO withDynamicLabel:NO to:touchAndControlSection];
@@ -832,10 +836,11 @@ BOOL isCustomResolution(int resolutionSelected) {
}
[self addSetting:self.touchModeStack2 ofId:@"touchModeStack2" withInfoTag:NO withDynamicLabel:NO to:experimentalSection];
- [self.touchModeSelector2 setEnabled:false];
+ // [self.touchModeSelector2 setEnabled:false];
[self addSetting:self.touchMoveEventIntervalStack ofId:@"touchMoveEventIntervalStack" withInfoTag:NO withDynamicLabel:YES to:experimentalSection];
[self addSetting:self.relativeTouchSlideThresholdStack ofId:@"relativeTouchSlideThresholdStack" withInfoTag:YES withDynamicLabel:YES to:experimentalSection];
[self addSetting:self.singleTapSensitivityStack ofId:@"singleTapSensitivityStack" withInfoTag:NO withDynamicLabel:YES to:experimentalSection];
+ [self addSetting:self.leftClickDelayStack ofId:@"leftClickDelayStack" withInfoTag:NO withDynamicLabel:YES to:experimentalSection];
[self addSetting:self.renderingBackendStack ofId:@"renderingBackendStack" withInfoTag:YES withDynamicLabel:NO to:experimentalSection];
[self addSetting:self.performanceGraphStack ofId:@"performanceGraphStack" withInfoTag:YES withDynamicLabel:NO to:experimentalSection];
[self addDynamicLabelForStack:self.graphOpacityStack];
@@ -970,12 +975,14 @@ BOOL isCustomResolution(int resolutionSelected) {
}];
}
-- (void)highlightedBackgroundForView:(UIView* )view animateWithDuration:(CGFloat)duration{
+- (void)highlightedBackgroundForView:(UIView* )view animateWithDuration:(CGFloat)duration completion: (void (^)(void))completion{
[UIView animateWithDuration:duration animations:^{
view.layer.cornerRadius = 6;
view.layer.masksToBounds = YES;
view.clipsToBounds = YES;
view.backgroundColor = [ThemeManager appPrimaryColorWithAlpha];
+ } completion:^(BOOL finished){
+ completion();
}];
}
@@ -994,7 +1001,7 @@ BOOL isCustomResolution(int resolutionSelected) {
settingStackWillBeRelocatedToLowestPosition = true;
}
else{
- [self highlightedBackgroundForView:currentStack animateWithDuration:0];
+ [self highlightedBackgroundForView:currentStack animateWithDuration:0 completion:nil];
snapshot.backgroundColor = [UIColor clearColor];
}
}
@@ -1052,7 +1059,7 @@ BOOL isCustomResolution(int resolutionSelected) {
if(currentSettingsMenuMode == AllSettings &&gesture.state == UIGestureRecognizerStateBegan) {
[self findCapturedStackByTouchLocation:locationInParentStack];
if(capturedStack == nil) return;
- [self highlightedBackgroundForView:capturedStack animateWithDuration:0];
+ [self highlightedBackgroundForView:capturedStack animateWithDuration:0 completion:nil];
UIAlertController* actionSheet = [self prepareAddToFavoriteActionSheet];
actionSheet.popoverPresentationController.sourceView = capturedStack;
[self presentViewController:actionSheet animated:YES completion:nil];
@@ -1300,6 +1307,11 @@ BOOL isCustomResolution(int resolutionSelected) {
showOnlineDocAction = true;
onlineDocLink = [LocalizationHelper localizedStringForKey:@"relativeTouchSlideThresholdStackLink"];
}
+ if([sender.superview.accessibilityIdentifier isEqualToString: @"ctrlDownForPinchStack"]){
+ tipText = [LocalizationHelper localizedStringForKey:@"ctrlDownForPinchStackTip"];
+ showOnlineDocAction = false;
+ }
+
UIAlertController *tipsAlertController = [UIAlertController alertControllerWithTitle: [LocalizationHelper localizedStringForKey:@"Tips"] message:tipText preferredStyle:UIAlertControllerStyleAlert];
@@ -1731,7 +1743,7 @@ BOOL isCustomResolution(int resolutionSelected) {
[self.duckOtherAppSwitch setOn:self->tempSettings.duckOtherApps];
- [self.muteInBackgroundSwitch setOn:tempSettings.muteInBackground];
+ [self.muteInBackgroundSwitch setOn:self->tempSettings.muteInBackground];
[self.muteInBackgroundSwitch addTarget:self action:@selector(muteInBackgroundSwitchFlipped:) forControlEvents:UIControlEventValueChanged];
[self.micVolumeSlider setValue:self->tempSettings.micVolume.floatValue*100];
@@ -1856,8 +1868,13 @@ BOOL isCustomResolution(int resolutionSelected) {
[self.mousePointerVelocityFactorSlider addTarget:self action:@selector(mousePointerVelocityFactorSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved.
[self mousePointerVelocityFactorSliderMoved:self.mousePointerVelocityFactorSlider];
+ [self.passthroughGesturesSwitch setOn:self->tempSettings.passthroughGestures];
+ [self.passthroughGesturesSwitch addTarget:self action:@selector(passthroughGesturesSwitchFlipped:) forControlEvents:(UIControlEventValueChanged)];
+
[self.pinchGestureSwitch setOn:self->tempSettings.enablePinch];
[self.pinchGestureSwitch addTarget:self action:@selector(pinchGestureSwitchFlipped:) forControlEvents:(UIControlEventValueChanged)];
+
+ [self.ctrlDownForPinchSwitch setOn:self->tempSettings.ctrlDownForPinch];
[self.scrollSensitivitySlider setValue:self->tempSettings.scrollSensitivity.floatValue animated:NO];
[self.scrollSensitivitySlider addTarget:self action:@selector(scrollSensitivitySliderMoved:) forControlEvents:(UIControlEventValueChanged)];
@@ -1895,12 +1912,19 @@ BOOL isCustomResolution(int resolutionSelected) {
[self.touchMoveEventIntervalSlider addTarget:self action:@selector(touchMoveEventIntervalSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved.
[self touchMoveEventIntervalSliderMoved:self.touchMoveEventIntervalSlider];
+ // touch move event interval for native-touch.
+ [self.leftClickDelaySlider setValue:self->tempSettings.leftClickDelayMs.intValue animated:NO]; // Load old setting.
+ [self.leftClickDelaySlider addTarget:self action:@selector(leftClickDelaySliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved.
+ [self leftClickDelaySliderMoved:self.leftClickDelaySlider];
// this part will enable/disable oscSelector & the asyncNativeTouchPriority selector
uint8_t touchModeSelectorIndex = self->tempSettings.touchMode.intValue == NativeTouchOnly ? NativeTouch : self->tempSettings.touchMode.intValue;
- [self.touchModeSelector setSelectedSegmentIndex:touchModeSelectorIndex]; //Load old touchMode setting
- [self.touchModeSelector addTarget:self action:@selector(touchModeChanged:) forControlEvents:UIControlEventValueChanged];
- [self touchModeChanged:self.touchModeSelector];
+ [self.touchModeSelector1 setSelectedSegmentIndex:touchModeSelectorIndex]; //Load old touchMode setting
+ [self.touchModeSelector1 addTarget:self action:@selector(touchMode1Changed:) forControlEvents:UIControlEventValueChanged];
+ [self touchModeChanged:self.touchModeSelector1];
+
+ [self.touchModeSelector2 addTarget:self action:@selector(touchMode2Changed:) forControlEvents:UIControlEventValueChanged];
+
// self.enableOswSwitchStack.hidden = !(self->tempSettings.touchMode.intValue == NativeTouch || self->tempSettings.touchMode.intValue == NativeTouchOnly); // do not use setHidden to stack wrapped by a settingStack
@@ -1927,7 +1951,7 @@ BOOL isCustomResolution(int resolutionSelected) {
completion:^{
if(!CountdownAlertController.actionCancelled){
[weakSelf.onScreenWidgetSelector setSelectedSegmentIndex:OnScreenControlsLevelCustom];
- if(weakSelf.touchModeSelector.selectedSegmentIndex == NativeTouch){
+ if(weakSelf.touchModeSelector1.selectedSegmentIndex == NativeTouch){
[weakSelf.enableOswForNativeTouchSwitch setOn:true];
[weakSelf enableOswForNativeTouchSwitchFlipped:weakSelf.enableOswForNativeTouchSwitch];
}
@@ -2013,7 +2037,7 @@ BOOL isCustomResolution(int resolutionSelected) {
}
- (bool)isNotNativeTouchOnly{
- return (self.enableOswForNativeTouchSwitch.isOn && self.touchModeSelector.selectedSegmentIndex == NativeTouch) || self.touchModeSelector.selectedSegmentIndex != NativeTouch;
+ return (self.enableOswForNativeTouchSwitch.isOn && self.touchModeSelector1.selectedSegmentIndex == NativeTouch) || self.touchModeSelector1.selectedSegmentIndex != NativeTouch;
}
- (void)handleOswGestureChange{
@@ -2357,14 +2381,32 @@ BOOL isCustomResolution(int resolutionSelected) {
}
*/
+- (void)touchMode2Changed:(UISegmentedControl* )sender {
+ // [UIView animateWithDuration:0 animations:^{
+ [self.touchModeSelector1 setSelectedSegmentIndex: sender.selectedSegmentIndex];
+ // } completion:^(BOOL finished) {
+ // 动画完成时执行的代码
+ [self touchModeChanged:sender];
+ // }];
+}
+
+- (void)touchMode1Changed:(UISegmentedControl* )sender {
+ // [UIView animateWithDuration:0 animations:^{
+ self.touchModeSelector2.selectedSegmentIndex = sender.selectedSegmentIndex;
+ // } completion:^(BOOL finished) {
+ // 动画完成时执行的代码
+ [self touchModeChanged:sender];
+ // }];
+}
+
- (void)touchModeChanged:(UISegmentedControl* )sender {
// Disable On-Screen Controls & Widgets in non-relative touch mode
// bool customOscEnabled = [self isOswEnabled] && [self.onScreenWidgetSelector selectedSegmentIndex] == OnScreenControlsLevelCustom;
- self.touchModeSelector2.selectedSegmentIndex = sender.selectedSegmentIndex;
bool isNativeTouch = sender.selectedSegmentIndex == NativeTouch;
- //bool asyncNativeTouchEnabled = [self.asyncNativeTouchPrioritySelector selectedSegmentIndex] != AsyncNativeTouchOff;
- if(self.enableOswSwitchStack.hidden != !isNativeTouch && isNativeTouch) [self highlightEmergingStack:self.enableOswSwitchStack];
+ bool isEgmerging = self.enableOswSwitchStack.hidden != !isNativeTouch && isNativeTouch;
self.enableOswSwitchStack.hidden = !isNativeTouch;
+ if(isEgmerging) [self highlightEmergingStack:self.enableOswSwitchStack];
+
[self setHidden:!isNativeTouch forStack:self.pointerVelocityDividerStack];
@@ -2373,14 +2415,28 @@ BOOL isCustomResolution(int resolutionSelected) {
[self setHidden:!isNativeTouch forStack:self.pointerVelocityFactorStack];
[self setHidden:!isNativeTouch forStack:self.touchMoveEventIntervalStack];
+ /*
[self setHidden:(sender.selectedSegmentIndex!=RelativeTouch
&& sender.selectedSegmentIndex!=AbsoluteTouch) forStack:self.pinchGestureStack];
[self setHidden:(sender.selectedSegmentIndex!=RelativeTouch
- && sender.selectedSegmentIndex!=AbsoluteTouch) forStack:self.scrollSensitivityStack];
+ && sender.selectedSegmentIndex!=AbsoluteTouch) forStack:self.scrollSensitivityStack];*/
+
+ [self setHidden:sender.selectedSegmentIndex!=AbsoluteTouch forStack:self.passthroughGesturesStack];
+ UISwitch* dummySwitch = [[UISwitch alloc] init];
+ [dummySwitch setOn:(sender.selectedSegmentIndex==RelativeTouch
+ || (sender.selectedSegmentIndex==AbsoluteTouch && _passthroughGesturesSwitch.isOn))];
+ [self passthroughGesturesSwitchFlipped:dummySwitch];
+
+ /*
[self setHidden:((sender.selectedSegmentIndex!=RelativeTouch
&& sender.selectedSegmentIndex!=AbsoluteTouch)
|| !_pinchGestureSwitch.isOn) forStack:self.pinchSensitivityStack];
+ [self setHidden:((sender.selectedSegmentIndex!=RelativeTouch
+ && sender.selectedSegmentIndex!=AbsoluteTouch)
+ || !_pinchGestureSwitch.isOn) forStack:self.ctrlDownForPinchStack];*/
+ [self setHidden:sender.selectedSegmentIndex!=AbsoluteTouch forStack:self.leftClickDelayStack];
+
[self setHidden:sender.selectedSegmentIndex!=RelativeTouch forStack:self.mousePointerVelocityStack];
[self setHidden:sender.selectedSegmentIndex!=RelativeTouch forStack:self.singleTapSensitivityStack];
[self setHidden:sender.selectedSegmentIndex!=RelativeTouch forStack:self.relativeTouchSlideThresholdStack];
@@ -2431,16 +2487,22 @@ BOOL isCustomResolution(int resolutionSelected) {
}
}
+- (void)passthroughGesturesSwitchFlipped:(UISwitch* )sender{
+ [self setHidden:!sender.isOn forStack:_pinchGestureStack];
+ [self setHidden:!sender.isOn forStack:_scrollSensitivityStack];
+ if(!sender.isOn) [self pinchGestureSwitchFlipped:sender];
+ else [self pinchGestureSwitchFlipped:_pinchGestureSwitch];
+}
+
- (void)pinchGestureSwitchFlipped:(UISwitch* )sender{
[self setHidden:!sender.isOn forStack:_pinchSensitivityStack];
+ [self setHidden:!sender.isOn forStack:_ctrlDownForPinchStack];
}
- (void)highlightEmergingStack:(UIStackView* )stack{
- [self highlightedBackgroundForView:stack animateWithDuration:0.2];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
+ [self highlightedBackgroundForView:stack animateWithDuration:0.2 completion:^{
[self clearBackgroundColorForView:stack animateWithDuration:0.2];
- });
+ }];
}
- (void)muteInBackgroundSwitchFlipped:(UISwitch* )sender{
@@ -2652,6 +2714,9 @@ BOOL isCustomResolution(int resolutionSelected) {
[NSString stringWithFormat:@" %d μs ", (uint16_t)self.touchMoveEventIntervalSlider.value] : @"";
}
+- (void) leftClickDelaySliderMoved:(UISlider* )sender{
+ [self findDynamicLabelFromStack:self.leftClickDelayStack].text = [NSString stringWithFormat:@" %d ms ", (uint16_t)sender.value];
+}
- (void) slideToMenuDistanceSliderMoved:(UISlider* )sender{
UILabel* displayLabel = [self findDynamicLabelFromStack:_slideToSettingsDistanceStack];
@@ -2870,6 +2935,8 @@ BOOL isCustomResolution(int resolutionSelected) {
Settings* currentSettings = [dataMan retrieveSettings];
+ CGFloat settingsMenuOffset = _rememberFoldStateSwitch.isOn ? _scrollView.contentOffset.y : 0;
+
NSInteger height = self.mainFrameViewController.settingsExpandedInStreamView ? currentSettings.height.intValue : [self getChosenStreamHeight];
NSInteger width = self.mainFrameViewController.settingsExpandedInStreamView ? currentSettings.width.intValue : [self getChosenStreamWidth];
@@ -2912,7 +2979,7 @@ BOOL isCustomResolution(int resolutionSelected) {
BOOL enableYUV444 = self.yuv444Switch.isOn;
BOOL enablePIP = self.pipSwitch.isOn;
BOOL btMouseSupport = self.citrixX1MouseSwitch.isOn;
- NSInteger touchMode = [self isNotNativeTouchOnly] ? self.touchModeSelector.selectedSegmentIndex : NativeTouchOnly;
+ NSInteger touchMode = [self isNotNativeTouchOnly] ? self.touchModeSelector1.selectedSegmentIndex : NativeTouchOnly;
NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex];
BOOL statsOverlayEnabled = statsOverlayLevel != 0;
BOOL enableHdr = self.hdrSwitch.isOn;
@@ -2932,14 +2999,17 @@ BOOL isCustomResolution(int resolutionSelected) {
NSInteger hapticEngine = self.hapticEngineSelector.selectedSegmentIndex;
CGFloat edgeSlidingSensitivity = self.edgeSlidingSensitivitySlider.value;
NSInteger audioEngine = self.audioEngineSelector.selectedSegmentIndex;
- // BOOL delayLeftClick = self.delayLeftClickSwitch.isOn;
- BOOL delayLeftClick = true;
+ BOOL delayLeftClick = self.delayLeftClickSwitch.isOn;
+ // BOOL delayLeftClick = true;
BOOL duckOtherApps = self.duckOtherAppSwitch.isOn;
BOOL muteInBackground = self.muteInBackgroundSwitch.isOn;
CGFloat relativeTouchSlideThreshold = self.relativeTouchSlideThresholdSlider.value;
BOOL enablePinch = self.pinchGestureSwitch.isOn;
CGFloat scrollSensitivity = self.scrollSensitivitySlider.value;
CGFloat pinchSensitivity = self.pinchSensitivitySlider.value;
+ BOOL ctrlDownForPinch = self.ctrlDownForPinchSwitch.isOn;
+ CGFloat leftClickDelayMs = self.leftClickDelaySlider.value;
+ BOOL passthroughGestures = self.passthroughGesturesSwitch.isOn;
NSInteger backgroundSessionTimer = self.backgroundSessionTimerSlider.value == self.backgroundSessionTimerSlider.maximumValue ? (uint32_t) INT16_MAX : (uint32_t)self.backgroundSessionTimerSlider.value;
[dataMan saveSettingsWithBitrate:_bitrate
@@ -3002,6 +3072,10 @@ BOOL isCustomResolution(int resolutionSelected) {
enablePinch:enablePinch
scrollSensitivity:scrollSensitivity
pinchSensitivity:pinchSensitivity
+ ctrlDownForPinch:ctrlDownForPinch
+ leftClickDelayMs:leftClickDelayMs
+ settingsMenuOffset:settingsMenuOffset
+ passthroughGestures:passthroughGestures
backgroundSessionTimer:backgroundSessionTimer];
}
diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m
index 8284f792..6373dba3 100644
--- a/VoidLink/ViewControllers/StreamFrameViewController.m
+++ b/VoidLink/ViewControllers/StreamFrameViewController.m
@@ -310,11 +310,6 @@
}
-- (void)handleAbsTouchPanGesture:(UIPanGestureRecognizer* )gesture{
- NSLog(@"handleAbsTouchPanGesture %f", CACurrentMediaTime());
- LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
-}
-
- (void)configZoomGestureAndAddStreamView{
if (_settings.touchMode.intValue == AbsoluteTouch) {
if(!_scrollView) _scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
@@ -322,17 +317,17 @@
[_scrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
[_scrollView.panGestureRecognizer setMaximumNumberOfTouches:2]; // reduce competing with keyboardToggleRecognizer in StreamView.
#endif
- [_scrollView.panGestureRecognizer addTarget:self action:@selector(handleAbsTouchPanGesture:)];
[_scrollView setShowsHorizontalScrollIndicator:NO];
[_scrollView setShowsVerticalScrollIndicator:NO];
[_scrollView setDelegate:self];
- [_scrollView setMaximumZoomScale:1.0f];
+ [_scrollView setMaximumZoomScale:_settings.passthroughGestures ? 1.0 : 10.0f];
if(!_mainFrameViewcontroller.settingsExpandedInStreamView){
// Add StreamView inside a UIScrollView for absolute mode
[_scrollView addSubview:_streamView];
// Insert at index 0 to ensure it doesn't cover OSC controls (CALayers)
[self.view insertSubview:_scrollView atIndex:0];
}
+ _scrollView.panGestureRecognizer.enabled = !_settings.passthroughGestures;
}
else{
// Add streamView directly to self.view in other touch modes
@@ -453,6 +448,7 @@
[_streamView.onScreenControls sendInstance];
TouchPadGestureHandler.enablePinch = _settings.enablePinch;
+ TouchPadGestureHandler.ctrlDownForPinch = _settings.ctrlDownForPinch;
TouchPadGestureHandler.scrollSensitivity = _settings.scrollSensitivity.floatValue;
TouchPadGestureHandler.pinchSensitivity = _settings.pinchSensitivity.floatValue;
diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings
index 3aeea0e1..5d53aaec 100644
--- a/VoidLink/mul.lproj/iPad.xcstrings
+++ b/VoidLink/mul.lproj/iPad.xcstrings
@@ -583,7 +583,7 @@
},
"zh-HK" : {
"stringUnit" : {
- "state" : "needs_review",
+ "state" : "translated",
"value" : "延遲滑鼠左單擊"
}
}
@@ -811,6 +811,36 @@
}
}
},
+ "aDg-5A-6M9.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Left Click Delay\"; ObjectID = \"aDg-5A-6M9\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Left Click Delay"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左单击延迟"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左單擊延遲"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左單擊延遲"
+ }
+ }
+ }
+ },
"AeU-kl-XFa.text" : {
"comment" : "Class = \"UILabel\"; text = \"Local Volume\"; ObjectID = \"AeU-kl-XFa\";",
"extractionState" : "extracted_with_value",
@@ -1447,6 +1477,36 @@
}
}
},
+ "BsJ-eo-2Ac.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Ctrl Down for Pinch\"; ObjectID = \"BsJ-eo-2Ac\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Ctrl Down for Pinch"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合时按下Ctrl"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合時按下Ctrl"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合時按下Ctrl"
+ }
+ }
+ }
+ },
"c1r-Hf-b7t.text" : {
"comment" : "Class = \"UILabel\"; text = \"Down button\"; ObjectID = \"c1r-Hf-b7t\";",
"extractionState" : "extracted_with_value",
@@ -1885,6 +1945,36 @@
}
}
},
+ "dfj-BB-Vby.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Passthrough Gestures\"; ObjectID = \"dfj-BB-Vby\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Passthrough Gestures"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透传手势"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透傳手勢"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透傳手勢"
+ }
+ }
+ }
+ },
"dOF-FW-cBU.text" : {
"comment" : "Class = \"UILabel\"; text = \" \"; ObjectID = \"dOF-FW-cBU\";",
"extractionState" : "extracted_with_value",
diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings
index df7d26b3..fe161a51 100644
--- a/VoidLink/mul.lproj/iPhone.xcstrings
+++ b/VoidLink/mul.lproj/iPhone.xcstrings
@@ -373,6 +373,36 @@
}
}
},
+ "5S1-w1-Wnq.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Left Click Delay\"; ObjectID = \"5S1-w1-Wnq\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Left Click Delay"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左单击延迟"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左單擊延遲"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "左單擊延遲"
+ }
+ }
+ }
+ },
"5uF-E5-hpX.text" : {
"comment" : "Class = \"UILabel\"; text = \"On-Screen Widgets \"; ObjectID = \"5uF-E5-hpX\";",
"extractionState" : "extracted_with_value",
@@ -1009,6 +1039,36 @@
}
}
},
+ "A5m-3n-5qc.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Passthrough Gestures\"; ObjectID = \"A5m-3n-5qc\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Passthrough Gestures"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透传手势"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透傳手勢"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "透傳手勢"
+ }
+ }
+ }
+ },
"A9r-dE-rT4.segmentTitles[0]" : {
"comment" : "Class = \"UISegmentedControl\"; A9r-dE-rT4.segmentTitles[0] = \"Touchpad\"; ObjectID = \"A9r-dE-rT4\";",
"extractionState" : "extracted_with_value",
@@ -2377,6 +2437,36 @@
}
}
},
+ "ICY-9b-uFD.text" : {
+ "comment" : "Class = \"UILabel\"; text = \"Ctrl Down for Pinch\"; ObjectID = \"ICY-9b-uFD\";",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Ctrl Down for Pinch"
+ }
+ },
+ "zh-Hans" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合时按下Ctrl"
+ }
+ },
+ "zh-Hant" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合時按下Ctrl"
+ }
+ },
+ "zh-HK" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "捏合時按下Ctrl"
+ }
+ }
+ }
+ },
"Idx-O1-5dn.text" : {
"comment" : "Class = \"UILabel\"; text = \"Height\"; ObjectID = \"Idx-O1-5dn\";",
"extractionState" : "extracted_with_value",
@@ -3787,13 +3877,13 @@
},
"zh-Hans" : {
"stringUnit" : {
- "state" : "needs_review",
+ "state" : "translated",
"value" : "延迟鼠标左单击"
}
},
"zh-Hant" : {
"stringUnit" : {
- "state" : "needs_review",
+ "state" : "translated",
"value" : "延遲滑鼠左單擊"
}
},