- button widget skill combo enhanced to macro
- widget picker view UI fixes
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-6
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
+1350
-179
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,
|
||||
|
||||
Reference in New Issue
Block a user