- button widget skill combo enhanced to macro

- widget picker view UI fixes
This commit is contained in:
True Zhuanjia
2026-05-21 14:18:50 +08:00
parent a7088c70e5
commit 2c2088e4b1
11 changed files with 2057 additions and 312 deletions
+60 -44
View File
@@ -531,7 +531,7 @@ import UIKit
}
for (index, key) in validKeyStrings.enumerated() {
print("Valid Key \(index): \(key)")
// print("Valid Key \(index): \(key)")
}
return validKeyStrings
@@ -540,56 +540,72 @@ import UIKit
//super combo key button strings
@objc public func extractCmdStrings(from input: String) -> [String]? {
let input = input.uppercased()
let combinedStrings = [CommandManager.keyboardButtonMappings.keys.map { $0 as String },
CommandManager.oscButtonMappings.keys.map { $0 as String },
CommandManager.mouseButtonMappings.keys.map { $0 as String },
CommandManager.functionalButtonCmds.map { $0 as String },
CommandManager.motionControlButtonCmds.map { $0 as String },
CommandManager.touchPadCmds.map { $0 as String }
]
.lazy
.flatMap { $0 } // 三维展开
.map(String.init(describing:)) // 安全类型转换
let keys = combinedStrings.joined(separator: "|")
let pattern = "^(?:\(keys))(?:-(?:\(keys)))*(?:-\\d+MS)?$"
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
print("Failed to create regex")
return nil
}
let range = NSRange(location: 0, length: input.utf16.count)
guard let match = regex.firstMatch(in: input, options: [], range: range) else {
print("No match found for input: \(input)")
return nil
}
// print("Regex matched for input: \(input)")
let matchedString = (input as NSString).substring(with: match.range(at: 0))
let cmdStrings = matchedString.split(separator: "-").map { String($0) }
guard !cmdStrings.isEmpty else {
print("No key strings found in the matched string")
return nil
}
var validCmdStrings: [String] = []
for key in cmdStrings {
validCmdStrings.append(key)
if GenericUtils.isGUIWidgetPickerAvailable {
let cmdStrings = input
.split(separator: "-")
.map { String($0) }
guard !cmdStrings.isEmpty else {
print("No key strings found in the input string")
return nil
}
for key in cmdStrings {
validCmdStrings.append(key)
}
}
if validCmdStrings.isEmpty {
print("No valid key strings found in the matched string")
return nil
else {
let input = input.uppercased()
let combinedStrings = [CommandManager.keyboardButtonMappings.keys.map { $0 as String },
CommandManager.oscButtonMappings.keys.map { $0 as String },
CommandManager.mouseButtonMappings.keys.map { $0 as String },
CommandManager.functionalButtonCmds.map { $0 as String },
CommandManager.motionControlButtonCmds.map { $0 as String },
CommandManager.touchPadCmds.map { $0 as String }
]
.lazy
.flatMap { $0 } // 三维展开
.map(String.init(describing:)) // 安全类型转换
let keys = combinedStrings.joined(separator: "|")
let pattern = "^(?:\(keys))(?:-(?:\(keys)))*(?:-\\d+MS)?$"
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
print("Failed to create regex")
return nil
}
let range = NSRange(location: 0, length: input.utf16.count)
guard let match = regex.firstMatch(in: input, options: [], range: range) else {
print("No match found for input: \(input)")
return nil
}
// print("Regex matched for input: \(input)")
let matchedString = (input as NSString).substring(with: match.range(at: 0))
let cmdStrings = matchedString.split(separator: "-").map { String($0) }
guard !cmdStrings.isEmpty else {
print("No key strings found in the matched string")
return nil
}
for key in cmdStrings {
validCmdStrings.append(key)
}
if validCmdStrings.isEmpty {
print("No valid key strings found in the matched string")
return nil
}
}
for (index, key) in validCmdStrings.enumerated() {
print("Valid Key \(index): \(key)")
}
return validCmdStrings
}
+122 -38
View File
@@ -453,17 +453,6 @@ import ObjectiveC.runtime
// 安全解包并处理 `comboKeyStrings`
if var comboStrings = CommandManager.shared.extractCmdStrings(from: self.cmdString) {
// extract timeInterval
if let lastString = comboStrings.last, lastString.contains("MS") {
// 移除 "MS" 后的部分并转换为整数
let timeIntervalString = lastString.replacingOccurrences(of: "MS", with: "")
// 安全地将字符串转换为整数
if let timeInterval = UInt32(timeIntervalString) {
self.comboKeyTimeIntervalMs = timeInterval
} else {print("无法将时间字符串转换为整数")}
comboStrings.removeLast()
}
if CommandManager.touchPadCmds.contains(comboStrings.first ?? "") {self.widgetType = WidgetTypeEnum.touchPad}
else {self.widgetType = WidgetTypeEnum.button}
@@ -1322,6 +1311,9 @@ import ObjectiveC.runtime
let indicatorFrame = CAShapeLayer();
indicatorFrame.frame = CGRectMake(0, 0, 75*highlightSizeFactor, 75*highlightSizeFactor)
indicatorFrame.cornerRadius = 23 * highlightSizeFactor
if #available(iOS 13.0, *) {
indicatorFrame.cornerCurve = .continuous
}
directionLayer.borderWidth = 5.3 * min(1.0, highlightSizeFactor)
directionLayer.frame = indicatorFrame.bounds.insetBy(dx: -directionLayer.borderWidth, dy: -directionLayer.borderWidth) // Adjust the inset as needed
directionLayer.cornerRadius = indicatorFrame.cornerRadius + directionLayer.borderWidth
@@ -1896,44 +1888,136 @@ import ObjectiveC.runtime
}
//==============================================================================
private func sendComboButtonsDownEvent(comboStrings: [String]) {
private var hasUnifiedTriggerInterval: Bool {
if let lastString = comboButtonStrings.last, lastString.contains("MS") {
return true
}
else {return false}
}
private func getMilliSecIntervalFrom(intervalString: String?) -> UInt32{
guard let timeIntervalString = intervalString?.replacingOccurrences(of: "MS", with: "") else { return 0 }
if let timeInterval = UInt32(timeIntervalString) {
return timeInterval
}
else {return 0}
}
private func getMilliSecIntervalFrom(cmdString: String) -> UInt32{
if cmdString.contains(".") {
let intervalString = cmdString.split(separator: ".").last.map(String.init)
return getMilliSecIntervalFrom(intervalString: intervalString)
}
else {return 0}
}
private func handleButtonStringDown(_ buttonString: String) {
let realButtonString: String
if buttonString.contains(".") {
realButtonString = buttonString.split(separator: ".").first.map(String.init)!
DispatchQueue.global().asyncAfter(deadline: .now() + Double(getMilliSecIntervalFrom(cmdString: buttonString))/1000) {
self.handleButtonStringUp(realButtonString)
}
}
else {realButtonString = buttonString}
DispatchQueue.global(qos: .userInteractive).async {
for comboString in comboStrings {
if CommandManager.oscButtonMappings.keys.contains(comboString) {
self.sendOscButtonDownEvent(oscString: comboString)
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = true}
if CommandManager.oscButtonMappings.keys.contains(realButtonString) {
self.sendOscButtonDownEvent(oscString: realButtonString)
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = true}
}
if CommandManager.keyboardButtonMappings.keys.contains(realButtonString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[realButtonString]!,Int8(KEY_ACTION_DOWN), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(realButtonString), self.functionalButtonString != "ABSTCHDRAG" {
let button = Int32(CommandManager.mouseButtonMappings[realButtonString]!)
if abs(button) == 0xFF {
LiSendScrollEvent(button>0 ? 3 : -3)
}
if CommandManager.keyboardButtonMappings.keys.contains(comboString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[comboString]!,Int8(KEY_ACTION_DOWN), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(comboString), self.functionalButtonString != "ABSTCHDRAG" {
let button = Int32(CommandManager.mouseButtonMappings[comboString]!)
if abs(button) == 0xFF {
LiSendScrollEvent(button>0 ? 3 : -3)
else {LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), button)}
}
}
}
private func sendComboButtonsDownEvent(comboStrings: [String]) {
let hasUnifiedTriggerInterval = self.hasUnifiedTriggerInterval
if hasUnifiedTriggerInterval {
self.comboKeyTimeIntervalMs = self.getMilliSecIntervalFrom(intervalString: comboStrings.last!)
}
if #available(iOS 13.0, *) {
Task {
for cmdString in comboStrings {
let isIntervalCmd = cmdString.contains("MS")
let triggerDelay = hasUnifiedTriggerInterval
? self.comboKeyTimeIntervalMs :
( isIntervalCmd ? self.getMilliSecIntervalFrom(intervalString: cmdString) : 0)
if hasUnifiedTriggerInterval || !isIntervalCmd {
self.handleButtonStringDown(cmdString)
}
if cmdString != comboStrings.last {
try? await Task.sleep(nanoseconds: UInt64(triggerDelay)*1_000_000)
}
else {LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), button)}
}
if comboString != comboStrings.last {
usleep(self.comboKeyTimeIntervalMs*1000) // delay xxx ms
}
} else {
DispatchQueue.global(qos: .userInteractive).async {
for comboString in comboStrings {
self.handleButtonStringDown(comboString)
if comboString != comboStrings.last {
usleep(hasUnifiedTriggerInterval ? self.comboKeyTimeIntervalMs*1000 : 0) // delay xxx ms
}
}
}
}
}
private func sendComboButtonsUpEvent(comboStrings: [String]) {
private func handleButtonStringUp(_ buttonString: String) {
if buttonString.contains(".") {return}
DispatchQueue.global(qos: .userInteractive).async {
for comboString in comboStrings {
if CommandManager.oscButtonMappings.keys.contains(comboString) {
self.sendOscButtonUpEvent(oscString: comboString)
if CommandManager.oscButtonMappings.keys.contains(buttonString) {
self.sendOscButtonUpEvent(oscString: buttonString)
}
if CommandManager.keyboardButtonMappings.keys.contains(buttonString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[buttonString]!,Int8(KEY_ACTION_UP), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(buttonString) {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), Int32(CommandManager.mouseButtonMappings[buttonString]!))
}
}
}
private func sendComboButtonsUpEvent(comboStrings: [String]) {
let hasUnifiedTriggerInterval = self.hasUnifiedTriggerInterval
if hasUnifiedTriggerInterval {
self.comboKeyTimeIntervalMs = self.getMilliSecIntervalFrom(intervalString: comboStrings.last!)
}
if #available(iOS 13.0, *) {
Task {
for cmdString in comboStrings {
let isIntervalCmd = cmdString.contains("MS")
let triggerDelay = hasUnifiedTriggerInterval
? self.comboKeyTimeIntervalMs :
( isIntervalCmd ? self.getMilliSecIntervalFrom(intervalString: cmdString) : 0)
if hasUnifiedTriggerInterval || !isIntervalCmd {
self.handleButtonStringUp(cmdString)
}
if cmdString != comboStrings.last {
try? await Task.sleep(nanoseconds: UInt64(triggerDelay)*1_000_000)
}
}
if CommandManager.keyboardButtonMappings.keys.contains(comboString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[comboString]!,Int8(KEY_ACTION_UP), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(comboString) {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), Int32(CommandManager.mouseButtonMappings[comboString]!))
}
if comboString != comboStrings.last {
usleep(self.comboKeyTimeIntervalMs*1000) // delay xxx ms
}
} else {
DispatchQueue.global(qos: .userInteractive).async {
for comboString in comboStrings {
self.handleButtonStringUp(comboString)
if comboString != comboStrings.last {
self.handleButtonStringUp(comboString)
usleep(self.comboKeyTimeIntervalMs*1000) // delay xxx ms
}
}
}
}
+4 -12
View File
@@ -437,9 +437,7 @@ import UIKit
pickerViewController.initialTabIdentifier = "keyboard"
pickerViewController.shortcutIdentifier = "eraser"
pickerViewController.shortcutPickerTipText = LocalizationHelper.localizedString(forKey: "Select eraser shortcut keys")
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
viewController.present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: viewController)
return
}
@@ -489,9 +487,7 @@ import UIKit
pickerViewController.initialTabIdentifier = "keyboard"
pickerViewController.shortcutIdentifier = "brush"
pickerViewController.shortcutPickerTipText = LocalizationHelper.localizedString(forKey: "Select brush shortcut keys")
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
viewController.present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: viewController)
return
/*
@@ -551,9 +547,7 @@ import UIKit
pickerViewController.initialTabIdentifier = "keyboard"
pickerViewController.shortcutIdentifier = "squeezePress"
pickerViewController.shortcutPickerTipText = LocalizationHelper.localizedString(forKey: "squeezePressShortcutPickerTip")
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
viewController.present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: viewController)
}
/*
let oscProfileMan = OSCProfilesManager.sharedManager(CGRectZero)
@@ -604,9 +598,7 @@ import UIKit
pickerViewController.initialTabIdentifier = "keyboard"
pickerViewController.shortcutIdentifier = "squeezeRelease"
pickerViewController.shortcutPickerTipText = LocalizationHelper.localizedString(forKey: "squeezeReleaseShortcutPickerTip")
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
viewController.present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: viewController)
}
/*
+443 -29
View File
@@ -935,7 +935,7 @@
},
"zh-Hans" : {
"stringUnit" : {
"state" : "needs_review",
"state" : "translated",
"value" : "陀螺仪+右摇杆"
}
},
@@ -2100,6 +2100,29 @@
}
}
},
"Action mode" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "操作模式"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "操作模式"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "操作模式"
}
}
}
},
"Activate toolbox menu during streaming" : {
"extractionState" : "manual",
"localizations" : {
@@ -3390,6 +3413,29 @@
}
}
},
"Confirm" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "确定"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "確定"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "確定"
}
}
}
},
"Connecting" : {
"extractionState" : "manual",
"localizations" : {
@@ -3603,6 +3649,29 @@
}
}
},
"Continue adding controls to this combination, or tap button in the pool to set macro." : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "继续向此组合添加控件,或点按池中的按钮以设置宏。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "繼續向此組合加入控制項,或點按池中的按鈕以設定巨集。"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "繼續向此組合加入控制項,或點按池中的按鈕以設定巨集。"
}
}
}
},
"Controller" : {
"extractionState" : "manual",
"localizations" : {
@@ -6427,6 +6496,29 @@
}
}
},
"Gyro button" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺仪开关"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺儀開關"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺儀開關"
}
}
}
},
"Gyro Button" : {
"extractionState" : "manual",
"localizations" : {
@@ -6519,29 +6611,6 @@
}
}
},
"Gyro switch button" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺仪切换按键"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺儀切換按鍵"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "陀螺儀切換按鍵"
}
}
}
},
"Gyro widgets cannot be combined with direction pad" : {
"extractionState" : "manual",
"localizations" : {
@@ -6842,6 +6911,29 @@
}
}
},
"Hold until release" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "按压直至松开"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓直至鬆開"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓直至鬆開"
}
}
}
},
"Host information updated" : {
"extractionState" : "manual",
"localizations" : {
@@ -10183,6 +10275,98 @@
}
}
},
"Press duration" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "按压时长"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓時長"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓時長"
}
}
}
},
"Press duration: %d ms" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "按压时长: %d ms"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓時長: %d ms"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "按壓時長: %d ms"
}
}
}
},
"Manually enter press duration in milliseconds" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "手动输入按压时长, 单位毫秒"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "手動輸入按壓時長, 單位毫秒"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "手動輸入按壓時長, 單位毫秒"
}
}
}
},
"Manually enter trigger interval in milliseconds" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "手动输入间隔,单位毫秒"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "手動輸入間隔,單位毫秒"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "手動輸入間隔,單位毫秒"
}
}
}
},
"Press the button for mouse left button" : {
"extractionState" : "manual",
"localizations" : {
@@ -10229,6 +10413,29 @@
}
}
},
"Pressed for %dms" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "↓ %dms"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "↓ %dms"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "↓ %dms"
}
}
}
},
"Pressure curve" : {
"extractionState" : "manual",
"localizations" : {
@@ -12912,6 +13119,52 @@
}
}
},
"tap" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "单击"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "單擊"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "單擊"
}
}
}
},
"Tap" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "单击"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "單擊"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "單擊"
}
}
}
},
"Tap 'OK' to set on-screen widget to 'Custom' and enable motion control." : {
"extractionState" : "manual",
"localizations" : {
@@ -13234,6 +13487,29 @@
}
}
},
"Timed release" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "定时松开"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "定時鬆開"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "定時鬆開"
}
}
}
},
"Tips" : {
"extractionState" : "manual",
"localizations" : {
@@ -14487,25 +14763,163 @@
}
}
},
"You can continue adding controls to this combination" : {
"Insert trigger interval" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "你可以继续向此组合添加控件"
"value" : "插入触发间隔"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "你可以繼續向此組合加入控制項"
"value" : "插入觸發間隔"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "你可以繼續向此組合加入控制項"
"value" : "插入觸發間隔"
}
}
}
},
"Not enough room to insert trigger interval slots" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "没有足够空间插入触发间隔格"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "沒有足夠空間插入觸發間隔格"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "沒有足夠空間插入觸發間隔格"
}
}
}
},
"Select at least two button controls before inserting trigger intervals" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "请至少先选择两个按钮型控件,再插入触发间隔"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "請至少先選擇兩個按鈕型控制項,再插入觸發間隔"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "請至少先選擇兩個按鈕型控制項,再插入觸發間隔"
}
}
}
},
"Set all" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "统一设置间隔"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "統一設定間隔"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "統一設定間隔"
}
}
}
},
"Set this" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "单独设置间隔"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "單獨設定間隔"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "單獨設定間隔"
}
}
}
},
"Trigger interval cannot be inserted when WASDPAD or ARROWPAD is in the pool" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "池中存在 WASDPAD 或 ARROWPAD 时,不能插入触发间隔"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "池中存在 WASDPAD 或 ARROWPAD 時,不能插入觸發間隔"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "池中存在 WASDPAD 或 ARROWPAD 時,不能插入觸發間隔"
}
}
}
},
"Trigger interval slots are already inserted" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "触发间隔格已经插入"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "觸發間隔格已經插入"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "觸發間隔格已經插入"
}
}
}
@@ -14596,4 +15010,4 @@
}
},
"version" : "1.1"
}
}
+8
View File
@@ -434,6 +434,14 @@ import UIKit
return false
}
}()
@objc static let isGUIWidgetPickerAvailable: Bool = {
if #available(iOS 13.0, tvOS 13.0, *) {
return true
} else {
return false
}
}()
@objc static let menuSeparatorWidth: CGFloat = 0.7
@objc static let menuSectionSeparatorWidth: CGFloat = 0.7
@@ -1446,9 +1446,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
pickerViewController.delegate = self
pickerViewController.tabIdentifiers = ["gamepad", "keyboard", "functional"]
pickerViewController.initialTabIdentifier = "gamepad"
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: self)
return
}
@@ -1487,9 +1485,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
pickerViewController.initialCmdString = selectedWidget.cmdString
pickerViewController.initialButtonLabel = selectedWidget.widgetLabel
pickerViewController.initialShape = selectedWidget.shape
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: self)
return
}
@@ -292,9 +292,7 @@ import UIKit
pickerViewController.shortcutPickerNeedAlias = true
pickerViewController.tabIdentifiers = ["keyboard"]
pickerViewController.initialTabIdentifier = "keyboard"
let nav = UINavigationController(rootViewController: pickerViewController)
nav.modalPresentationStyle = .overFullScreen
self.present(nav, animated: true)
pickerViewController.presentOverFullScreen(from: self)
return
}
else{
@@ -399,6 +399,14 @@ struct AbstractGamepadView: View {
private func toggle(_ target: GamepadToggleTarget) {
if activeButtons.contains(target) {
if target.widgets.count == 1, let widget = target.widgets.first {
if canSelectCommand?(widget.cmd) == false {
return
}
AbstractGamepadView.selectedCmd = widget.cmd
onCommandSelected?(widget.cmd)
return
}
activeButtons.remove(target)
for widget in target.widgets {
onCommandDeselected?(widget.cmd)
+29
View File
@@ -368,6 +368,21 @@ struct VirtualKeyboardView: View {
let keyID = regularHighlightID(for: key)
if highlightedKeyIDs.contains(keyID) {
if mode != .shortcutPicker {
let cmd = key.cmdString(for: keyboardType) ?? ""
guard !cmd.isEmpty else { return }
if canSelectCommand?(cmd) == false {
return
}
VirtualKeyboardView.tappedKeyLabels = [key.label]
VirtualKeyboardView.selectedCmd = cmd
VirtualKeyboardView.lastSelectionDisplayText = poolDisplayText(for: key)
VirtualKeyboardView.lastSelectionUsesMacLayout = keyboardType == .mac
VirtualKeyboardView.lastSelectionFromMouseWidgets = isMouseWidgetKey(key)
VirtualKeyboardView.lastSelectionUsesFnCommandDisplay = usesFnCommandDisplay(for: key)
onCommandSelected?(cmd)
return
}
highlightedKeyIDs.remove(keyID)
if let cmd = key.cmdString(for: keyboardType), !cmd.isEmpty {
onCommandDeselected?(cmd)
@@ -406,6 +421,20 @@ struct VirtualKeyboardView: View {
}
if directionSingleKeyLabels.contains(key.label) {
if mode != .shortcutPicker {
let command = key.cmdString(for: keyboardType) ?? key.label
if canSelectCommand?(command) == false {
return
}
VirtualKeyboardView.tappedKeyLabels = [key.label]
VirtualKeyboardView.selectedCmd = command
VirtualKeyboardView.lastSelectionDisplayText = poolDisplayText(for: key)
VirtualKeyboardView.lastSelectionUsesMacLayout = keyboardType == .mac
VirtualKeyboardView.lastSelectionFromMouseWidgets = false
VirtualKeyboardView.lastSelectionUsesFnCommandDisplay = false
onCommandSelected?(command)
return
}
directionSingleKeyLabels.remove(key.label)
if let cmd = key.cmdString(for: keyboardType), !cmd.isEmpty {
onCommandDeselected?(cmd)
File diff suppressed because it is too large Load Diff
@@ -74,8 +74,12 @@ public final class WidgetPickerViewController: UIViewController {
view.addSubview(hostingViewController.view)
hostingViewController.didMove(toParent: self)
let hostingTopAnchor = UIDevice.current.userInterfaceIdiom == .phone
? view.safeAreaLayoutGuide.topAnchor
: view.topAnchor
NSLayoutConstraint.activate([
hostingViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
hostingViewController.view.topAnchor.constraint(equalTo: hostingTopAnchor),
hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
@@ -89,11 +93,31 @@ public final class WidgetPickerViewController: UIViewController {
navigationController?.setNavigationBarHidden(true, animated: false)
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
presentationState.hasHostAppeared = false
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
presentationState.hasHostAppeared = true
}
public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
presentationState.hasHostAppeared = false
coordinator.animate(alongsideTransition: nil) { [weak self] context in
guard let self else { return }
guard !context.isCancelled else {
self.presentationState.hasHostAppeared = true
return
}
self.presentationState.hasHostAppeared = true
}
}
private func resolvedTabs() -> [WidgetPickerTab] {
let tabs = tabIdentifiers.compactMap(WidgetPickerTab.init(identifier:))
return tabs.isEmpty ? WidgetPickerTab.allCases : tabs
@@ -104,6 +128,11 @@ public final class WidgetPickerViewController: UIViewController {
return WidgetPickerTab(identifier: initialTabIdentifier)
}
public func presentOverFullScreen(from presenter: UIViewController, animated: Bool = true) {
modalPresentationStyle = .overFullScreen
presenter.present(self, animated: animated)
}
public func presentAsOverlay(in parentViewController: UIViewController, animated: Bool = true) {
guard parent == nil else { return }
guard let originalAppWindow = parentViewController.view.window,