From cd415cc63941f3a9beac1922366db373d04e1909 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Sat, 18 Oct 2025 19:14:21 +0800 Subject: [PATCH] feat: setup autotap timer by text input instead of slider. --- VoidLink/Base.lproj/iPad.storyboard | 79 ++++++++++--------- VoidLink/Base.lproj/iPhone.storyboard | 69 ++++++++-------- VoidLink/Input/OnScreenWidgetView.swift | 71 +++++++++++++++++ VoidLink/Localization/Localizable.xcstrings | 46 +++++++++++ .../LayoutOnScreenControlsViewController.h | 6 +- .../LayoutOnScreenControlsViewController.m | 29 +++++-- VoidLink/mul.lproj/iPad.xcstrings | 4 +- VoidLink/mul.lproj/iPhone.xcstrings | 4 +- 8 files changed, 223 insertions(+), 85 deletions(-) diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard index 1f0a181e..dec89217 100644 --- a/VoidLink/Base.lproj/iPad.storyboard +++ b/VoidLink/Base.lproj/iPad.storyboard @@ -1360,16 +1360,16 @@ - + - + @@ -1847,7 +1847,7 @@ - + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - @@ -704,8 +705,8 @@ + - @@ -757,7 +758,7 @@ - + @@ -1754,16 +1755,16 @@ - + - + @@ -2357,19 +2358,19 @@ - + - + - + - + diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 1d39f93f..74edb6cc 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -1975,6 +1975,77 @@ import UIKit if self.buttonMode != ButtonMode.tapToToggle.rawValue {self.handleFingerUpOrSlideout()} } + @objc public func setAutoTapIntervalByText(str: String){ + self.autoTapInterval = self.parseTimeToMilliseconds(str) + } + + private func parseTimeToMilliseconds(_ input: String) -> Int { + // 最大值:24小时对应的毫秒数 + let maxMilliseconds = 24 * 60 * 60 * 1000 + + // 去除前后空白 + let trimmed = input.trimmingCharacters(in: .whitespacesAndNewlines) + + let pattern = #"^(\d+)(ms|s|m)?$"# + guard let regex = try? NSRegularExpression(pattern: pattern), + let match = regex.firstMatch(in: trimmed, range: NSRange(trimmed.startIndex..., in: trimmed)) else { + return 0 + } + + let valueRange = Range(match.range(at: 1), in: trimmed)! + let valueString = String(trimmed[valueRange]) + guard let value = Int(valueString) else { return 0 } + + var unit = "ms" + if let unitRange = Range(match.range(at: 2), in: trimmed) { + unit = String(trimmed[unitRange]) + } + + var milliseconds: Int + switch unit { + case "ms": + milliseconds = value + case "s": + milliseconds = value * 1000 + case "m": + milliseconds = value * 60 * 1000 + default: + return 0 + } + + // 小于 50 ms 的情况返回 0 + if milliseconds < 50 { + return 0 + } + + // 限制最大值 + if milliseconds > maxMilliseconds { + milliseconds = maxMilliseconds + } + + return milliseconds + } + + @objc public func getAutoTapIntervalStr() -> String { + // 边界限制:小于50ms的当作0,超过24小时的限制为24小时 + let maxMilliseconds = 24 * 60 * 60 * 1000 + if autoTapInterval < 50 { + return "" + } + let ms = min(autoTapInterval, maxMilliseconds) + + if ms % (60 * 1000) == 0 { + // 整分钟 + return "\(ms / (60 * 1000))m" + } else if ms % 1000 == 0 { + // 整秒 + return "\(ms / 1000)s" + } else { + // 毫秒 + return "\(ms)ms" + } + } + override func didMoveToSuperview() { super.didMoveToSuperview() if superview == nil { diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 6d6b1e1f..171858ad 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -858,6 +858,29 @@ } } }, + "Autotap timer " : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "连点定时器 " + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "連點定時器 " + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "連點定時器 " + } + } + } + }, "Back" : { "extractionState" : "manual", "localizations" : { @@ -3076,6 +3099,29 @@ } } }, + "Minimum: 50ms. 0 to disable. ms(milliSec),s(sec),m(min). ⏎ to save" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最低: 50ms, 输入0关闭. 单位: ms毫秒, s秒, m分钟. 按 ⏎ 保存设定值." + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "最低: 50 ms, 輸入 0 關閉. 單位:ms 秒, s秒, m分鐘. 按 ⏎ 儲存設定值." + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "最低: 50 ms, 輸入 0 關閉. 單位:ms 秒, s秒, m分鐘. 按 ⏎ 儲存設定值." + } + } + } + }, "ML_TEST_RESULT_INCONCLUSIVE" : { "extractionState" : "manual", "localizations" : { diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h index 0c3b5e20..b30a0a20 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h +++ b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h @@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN /** This view controller provides the user interface which allows the user to position on screen controller buttons anywhere they'd like on the screen. It also provides the user with the abilities to undo a change, save the on screen controller layout for later retrieval, and load previously saved controller layouts */ -@interface LayoutOnScreenControlsViewController : UIViewController +@interface LayoutOnScreenControlsViewController : UIViewController - (void)profileRefresh; - (void)reloadOnScreenWidgetViews; - (void)presentProfilesTableView; @@ -107,8 +107,8 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic) IBOutlet UIStackView *autoTapStack; @property (strong, nonatomic) IBOutlet UILabel *autoTapLabel; -@property (strong, nonatomic) IBOutlet UISlider *autoTapSlider; - +// @property (strong, nonatomic) IBOutlet UISlider *autoTapSlider; +@property (strong, nonatomic) IBOutlet UITextField *autoTapField; @property (weak, nonatomic) IBOutlet UIStackView *widgetPanelStack; diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index c7fb5a18..8ee999c2 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -774,6 +774,9 @@ OnScreenWidgetView* widgetView = (OnScreenWidgetView* )notification.object; self->widgetViewSelected = true; self->controllerLayerSelected = false; + + if(widgetView != selectedWidgetView) [selectedWidgetView setAutoTapIntervalByTextWithStr:_autoTapField.text]; + self->selectedWidgetView = widgetView; [self autoFitLabel:self.currentProfileLabel]; @@ -858,9 +861,17 @@ [self widgetBorderWidthSliderMoved:self.widgetBorderWidthSlider]; self.autoTapStack.hidden = !selectedWidgetView.hasAutoTap; - [self.autoTapSlider setValue:self->selectedWidgetView.autoTapInterval]; + // [self.autoTapSlider setValue:self->selectedWidgetView.autoTapInterval]; + [self.autoTapField setText:[self->selectedWidgetView getAutoTapIntervalStr]]; + self.autoTapField.textColor = [UIColor whiteColor]; + self.autoTapField.keyboardType = UIKeyboardTypeNumbersAndPunctuation; + self.autoTapField.attributedPlaceholder = + [[NSAttributedString alloc] initWithString:[LocalizationHelper localizedStringForKey:@"Minimum: 50ms. 0 to disable. ms(milliSec),s(sec),m(min). ⏎ to save"] + attributes:@{ + NSForegroundColorAttributeName:[[UIColor whiteColor] colorWithAlphaComponent:0.77] + }]; [self autoFitLabel:self.autoTapLabel]; - [self autoTapSliderMoved:self.autoTapSlider]; + // [self autoTapSliderMoved:self.autoTapSlider]; self.decelerationRateStack.hidden = !selectedWidgetView.hasTrackBall; [self.decelerationRateSlider setValue:selectedWidgetView.trackballDecelerationRate]; @@ -981,13 +992,14 @@ return; } +/* - (void)autoTapSliderMoved:(UISlider* )sender{ [self.autoTapLabel setText:(uint16_t)sender.value < 50 ? [LocalizationHelper localizedStringForKey: @"Auto tap disabled"] : [LocalizationHelper localizedStringForKey: @"Auto tap: %dms", (uint16_t)sender.value]]; if(self->selectedWidgetView != nil && self->widgetViewSelected){ selectedWidgetView.autoTapInterval = (uint16_t)sender.value; } return; -} +} */ - (void)mouseDownButtonChanged:(UISegmentedControl* )sender{ if(self->selectedWidgetView != nil && self->widgetViewSelected){ @@ -1169,8 +1181,9 @@ self.widgetBorderWidthLabel.text = [LocalizationHelper localizedStringForKey:@"Border width"]; self.borderWidthAlphaStack.hidden = YES; - [self.autoTapSlider addTarget:self action:@selector(autoTapSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; - self.autoTapLabel.text = [LocalizationHelper localizedStringForKey:@"Autotap"]; + // [self.autoTapSlider addTarget:self action:@selector(autoTapSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; + self.autoTapLabel.text = [LocalizationHelper localizedStringForKey:@"Autotap timer "]; + self.autoTapField.delegate = self; self.autoTapStack.hidden = YES; [self.sensitivityXSlider addTarget:self action:@selector(sensitivityXSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; @@ -1256,6 +1269,12 @@ } } +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; // 收起键盘 + [selectedWidgetView setAutoTapIntervalByTextWithStr:textField.text]; + return YES; +} + - (void)applyShadowForiOS13:(UIStackView* )stack { stack.backgroundColor = [UIColor clearColor]; diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings index d0feeff4..917d3ca6 100644 --- a/VoidLink/mul.lproj/iPad.xcstrings +++ b/VoidLink/mul.lproj/iPad.xcstrings @@ -914,13 +914,13 @@ } }, "And-W9-9NR.text" : { - "comment" : "Class = \"UILabel\"; text = \"Auto tap: 100ms\"; ObjectID = \"And-W9-9NR\";", + "comment" : "Class = \"UILabel\"; text = \"Auto tap\"; ObjectID = \"And-W9-9NR\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Auto tap: 100ms" + "value" : "Auto tap" } } } diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings index b2aead3a..d0c86188 100644 --- a/VoidLink/mul.lproj/iPhone.xcstrings +++ b/VoidLink/mul.lproj/iPhone.xcstrings @@ -2264,13 +2264,13 @@ } }, "IuG-44-1Je.text" : { - "comment" : "Class = \"UILabel\"; text = \"Autotap: 100ms\"; ObjectID = \"IuG-44-1Je\";", + "comment" : "Class = \"UILabel\"; text = \"Autotap\"; ObjectID = \"IuG-44-1Je\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Autotap: 100ms" + "value" : "Autotap" } } }