super combo custom on-screen button connected by "-" in key string

This commit is contained in:
TrueZhuangjia committed 2025-02-23 16:12:23 +08:00
1 parent 06e80823b8
commit 80804ee7ac
4 files changed
+198 -62

No files matched your search

+92 -17
View File
@@ -297,7 +297,7 @@ import UIKit
} }
// extractKeyStrings from keyboardCMDString // extractKeyStrings from keyboardCMDString
@objc public func extractKeyStrings(from input: String) -> [String]? { @objc public func extractKeyStringsFromComboCommand(from input: String) -> [String]? {
let keys = CommandManager.keyboardButtonMappings.keys.joined(separator: "|") let keys = CommandManager.keyboardButtonMappings.keys.joined(separator: "|")
let pattern = "^(?:(\(keys))(?:\\+(\(keys))*)*)$" let pattern = "^(?:(\(keys))(?:\\+(\(keys))*)*)$"
@@ -344,10 +344,60 @@ import UIKit
} }
//super combo key button strings
@objc public func extractKeyStringsFromComboKeys(from input: String) -> [String]? {
let combinedStrings = [CommandManager.keyboardButtonMappings.keys.map { $0 as String },
CommandManager.oscButtonMappings.keys.map { $0 as String },
CommandManager.mouseButtonMappings.keys.map { $0 as String }]
.lazy // 零内存开销
.flatMap { $0 } // 三维展开
.map(String.init(describing:)) // 安全类型转换
let keys = combinedStrings.joined(separator: "|")
// print(keys)
let pattern = "^(?:(\(keys))(?:\\-(\(keys))*)*)$"
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 keyStrings = matchedString.split(separator: "-").map { String($0) }
guard !keyStrings.isEmpty else {
print("No key strings found in the matched string")
return nil
}
var validKeyStrings: [String] = []
for key in keyStrings {
validKeyStrings.append(key)
}
if validKeyStrings.isEmpty {
print("No valid key strings found in the matched string")
return nil
}
for (index, key) in validKeyStrings.enumerated() {
print("Valid Key \(index): \(key)")
}
return validKeyStrings
}
@objc public func addCommand(_ command: RemoteCommand) -> Bool { @objc public func addCommand(_ command: RemoteCommand) -> Bool {
command.keyboardCmdString = command.keyboardCmdString.uppercased() // convert all letters to upper case command.keyboardCmdString = command.keyboardCmdString.uppercased() // convert all letters to upper case
if(command.alias.trimmingCharacters(in: .whitespacesAndNewlines).count == 0) {command.alias = command.keyboardCmdString} // copy cmd string as alias when alias is empty if(command.alias.trimmingCharacters(in: .whitespacesAndNewlines).count == 0) {command.alias = command.keyboardCmdString} // copy cmd string as alias when alias is empty
let keyStrings = extractKeyStrings(from: command.keyboardCmdString) let keyStrings = extractKeyStringsFromComboCommand(from: command.keyboardCmdString)
if (keyStrings == nil) {return false} // in case of non-keyboard command strings, return false if (keyStrings == nil) {return false} // in case of non-keyboard command strings, return false
commands.append(command) commands.append(command)
saveCommands() saveCommands()
@@ -393,25 +443,50 @@ import UIKit
} }
} }
@objc public func sendKeyDownEventWithDelay(keyboardCmdStrings: [String], delay: TimeInterval = 0.2, index: Int = 0) { // we need a large delay for WAN streaming @objc public func sendKeyComboCommand(keyboardCmdStrings: [String], delay: TimeInterval = 0.2, index: Int = 0) { // we need a large delay for WAN streaming
// 如果已处理完所有按键,则开始释放按键
guard index < keyboardCmdStrings.count else { guard index < keyboardCmdStrings.count else {
for keyStr in keyboardCmdStrings { // 释放按键
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[keyStr]!,Int8(KEY_ACTION_UP), 0) for keyStr in keyboardCmdStrings.reversed() { // 从后往前释放按键
if let keyCode = CommandManager.keyboardButtonMappings[keyStr] {
LiSendKeyboardEvent(keyCode, Int8(KEY_ACTION_UP), 0) // 释放按键
}
} }
return return
} // 如果已经处理完所有键,释放所有按键
let keyCode = CommandManager.keyboardButtonMappings[keyboardCmdStrings[index]]
guard let keyCode = keyCode else {
print("No mapping found for \(keyboardCmdStrings[index])")
sendKeyDownEventWithDelay(keyboardCmdStrings: keyboardCmdStrings, delay: delay, index: index+1) // 跳过当前键,继续下一个
return
} }
// 发送当前键的键盘按下事件
LiSendKeyboardEvent(keyCode,Int8(KEY_ACTION_DOWN), 0) // 获取当前按键的映射值
// 使用 asyncAfter 在指定异步延迟后发送下一个键的键盘按下事件 if let keyCode = CommandManager.keyboardButtonMappings[keyboardCmdStrings[index]] {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { // 发送当前按键的按下事件
self.sendKeyDownEventWithDelay(keyboardCmdStrings: keyboardCmdStrings, delay: delay, index: index+1) // 跳过当前键,继续下一个 LiSendKeyboardEvent(keyCode, Int8(KEY_ACTION_DOWN), 0)
// 延迟后递归处理下一个按键
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
self.sendKeyComboCommand(keyboardCmdStrings: keyboardCmdStrings, delay: delay, index: index + 1)
}
} else {
print("No mapping found for \(keyboardCmdStrings[index])")
// 如果当前按键没有映射,跳过当前按键并继续下一个
self.sendKeyComboCommand(keyboardCmdStrings: keyboardCmdStrings, delay: delay, index: index + 1)
} }
} }
@objc public func sendKeyComboDown(keyboardCmdStrings: [String]) { // we need a large delay for WAN streaming
for keyStr in keyboardCmdStrings {
if let keyCode = CommandManager.keyboardButtonMappings[keyStr] {
LiSendKeyboardEvent(keyCode, Int8(KEY_ACTION_DOWN), 0) // 释放按键
}
}
}
@objc public func sendKeyComboUp(keyboardCmdStrings: [String]) { // we need a large delay for WAN streaming
for keyStr in keyboardCmdStrings {
if let keyCode = CommandManager.keyboardButtonMappings[keyStr] {
LiSendKeyboardEvent(keyCode, Int8(KEY_ACTION_UP), 0) // 释放按键
}
}
return
}
} }
+101 -41
View File
@@ -659,7 +659,7 @@ import UIKit
private func setupButtonDownVisualEffectLayer() { private func setupButtonDownVisualEffectLayer() {
self.buttonDownVisualEffectWidth = 8.6 self.buttonDownVisualEffectWidth = 8
if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){
if widthFactor < 1.3 {self.buttonDownVisualEffectWidth = 15.3} // wider visual effect for osc buttons if widthFactor < 1.3 {self.buttonDownVisualEffectWidth = 15.3} // wider visual effect for osc buttons
else {self.buttonDownVisualEffectWidth = 9} else {self.buttonDownVisualEffectWidth = 9}
@@ -713,6 +713,60 @@ import UIKit
} }
//========================================================================================================== //==========================================================================================================
private func sendOscButtonDownEvent(keyString: String){
let buttonFlag = CommandManager.oscButtonMappings[keyString]
if buttonFlag != 0 {self.onScreenControls.pressDownControllerButton(buttonFlag!)}
if keyString == "OSCL2" {
self.onScreenControls.updateLeftTrigger(0xFF)
}
if keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0xFF)}
}
private func sendOscButtonUpEvent(keyString: String){
let buttonFlag = CommandManager.oscButtonMappings[keyString]
if buttonFlag != 0 {self.onScreenControls.releaseControllerButton(buttonFlag!)}
if keyString == "OSCL2" {self.onScreenControls.updateLeftTrigger(0x00)}
if keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0x00)}
}
//==============================================================================
private func sendComboButtonsDownEvent(comboStrings: [String]) {
DispatchQueue.global(qos: .userInitiated).async {
for comboString in comboStrings {
if CommandManager.oscButtonMappings.keys.contains(comboString) {
self.sendOscButtonDownEvent(keyString: comboString)
}
if CommandManager.keyboardButtonMappings.keys.contains(comboString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[comboString]!,Int8(KEY_ACTION_DOWN), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(comboString) {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), Int32(CommandManager.mouseButtonMappings[comboString]!))
}
usleep(10000) // delay 10ms
}
}
}
private func sendComboButtonsUpEvent(comboStrings: [String]) {
DispatchQueue.global(qos: .userInitiated).async {
for comboString in comboStrings {
if CommandManager.oscButtonMappings.keys.contains(comboString) {
self.sendOscButtonUpEvent(keyString: comboString)
}
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]!))
}
usleep(10000) //delay 10ms
}
}
}
//==============================================================================
// Touch event handling // Touch event handling
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
@@ -739,6 +793,7 @@ import UIKit
self.pressed = true self.pressed = true
if !OnScreenWidgetView.editMode { if !OnScreenWidgetView.editMode {
if CommandManager.touchPadCmds.contains(self.keyString) && touches.count == 1{ // don't use event?.allTouches?.count here, it will counts all touches including the ones captured by other UIViews if CommandManager.touchPadCmds.contains(self.keyString) && touches.count == 1{ // don't use event?.allTouches?.count here, it will counts all touches including the ones captured by other UIViews
switch self.keyString { switch self.keyString {
case "LSPAD": case "LSPAD":
@@ -771,31 +826,36 @@ import UIKit
} }
} }
if !CommandManager.touchPadCmds.contains(self.keyString) { if !self.keyString.contains("+") && !self.keyString.contains("-") {
self.buttonDownVisualEffect() // if there's no "+" in the keystring, treat it as a regular button:
if CommandManager.oscButtonMappings.keys.contains(self.keyString) {
self.sendOscButtonDownEvent(keyString: self.keyString)
}
if CommandManager.keyboardButtonMappings.keys.contains(self.keyString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[self.keyString]!,Int8(KEY_ACTION_DOWN), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(self.keyString) {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), Int32(CommandManager.mouseButtonMappings[self.keyString]!))
}
} }
if CommandManager.oscButtonMappings.keys.contains(self.keyString) { // if the command(keystring contains "-", it's a multi-type super combo button
let buttonFlag = CommandManager.oscButtonMappings[self.keyString] if self.keyString.contains("-"){
if buttonFlag != 0 {self.onScreenControls.pressDownControllerButton(buttonFlag!)} let comboStrings = CommandManager.shared.extractKeyStringsFromComboKeys(from: self.keyString)!
if self.keyString == "OSCL2" {self.onScreenControls.updateLeftTrigger(0xFF)} self.sendComboButtonsDownEvent(comboStrings: comboStrings)
if self.keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0xFF)}
} }
// if the command(keystring contains "+", it's a multi-key command or a quick triggering key, rather than a physical button // if the command(keystring contains "+", it's a multi-key command or a quick triggering key, rather than a physical button
if self.keyString.contains("+"){ if self.keyString.contains("+") && !self.keyString.contains("-"){
let keyboardCmdStrings = CommandManager.shared.extractKeyStrings(from: self.keyString)! let keyboardCmdStrings = CommandManager.shared.extractKeyStringsFromComboCommand(from: self.keyString)!
CommandManager.shared.sendKeyDownEventWithDelay(keyboardCmdStrings: keyboardCmdStrings) // send multi-key command CommandManager.shared.sendKeyComboCommand(keyboardCmdStrings: keyboardCmdStrings) // send multi-key command
DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) { // reset shadow color immediately 50ms later DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) { // reset shadow color immediately 50ms later
self.buttonUpVisualEffect() self.buttonUpVisualEffect()
} }
} }
// if there's no "+" in the keystring, treat it as a regular button:
if CommandManager.keyboardButtonMappings.keys.contains(self.keyString) { if !CommandManager.touchPadCmds.contains(self.keyString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[self.keyString]!,Int8(KEY_ACTION_DOWN), 0) self.buttonDownVisualEffect()
}
if CommandManager.mouseButtonMappings.keys.contains(self.keyString) {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), Int32(CommandManager.mouseButtonMappings[self.keyString]!))
} }
} }
// here is in edit mode: // here is in edit mode:
@@ -949,6 +1009,30 @@ import UIKit
break break
} }
} }
self.l3r3Indicator.removeFromSuperlayer()
self.upIndicator.removeFromSuperlayer()
self.downIndicator.removeFromSuperlayer()
self.leftIndicator.removeFromSuperlayer()
self.rightIndicator.removeFromSuperlayer()
self.lrudIndicatorBall.removeFromSuperlayer()
if !OnScreenWidgetView.editMode && !self.keyString.contains("+") && !self.keyString.contains("-") { // if the command(keystring contains "+", it's a multi-key command rather than a single key button
if CommandManager.oscButtonMappings.keys.contains(self.keyString) {
sendOscButtonUpEvent(keyString: self.keyString)
}
if CommandManager.keyboardButtonMappings.keys.contains(self.keyString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[self.keyString]!,Int8(KEY_ACTION_UP), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(self.keyString){
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), Int32(CommandManager.mouseButtonMappings[self.keyString]!))
}
}
// if the command(keystring contains "-", it's a multi-type super combo button
if !OnScreenWidgetView.editMode && self.keyString.contains("-"){
let comboStrings = CommandManager.shared.extractKeyStringsFromComboKeys(from: self.keyString)!
self.sendComboButtonsUpEvent(comboStrings: comboStrings)
}
if !OnScreenWidgetView.editMode && CommandManager.specialOverlayButtonCmds.contains(self.keyString){ if !OnScreenWidgetView.editMode && CommandManager.specialOverlayButtonCmds.contains(self.keyString){
if CACurrentMediaTime() - self.touchTapTimeStamp < 0.3 { if CACurrentMediaTime() - self.touchTapTimeStamp < 0.3 {
@@ -961,32 +1045,8 @@ import UIKit
} }
} }
self.buttonUpVisualEffect() self.buttonUpVisualEffect()
self.l3r3Indicator.removeFromSuperlayer()
self.upIndicator.removeFromSuperlayer()
self.downIndicator.removeFromSuperlayer()
self.leftIndicator.removeFromSuperlayer()
self.rightIndicator.removeFromSuperlayer()
self.lrudIndicatorBall.removeFromSuperlayer()
if CommandManager.oscButtonMappings.keys.contains(self.keyString) {
let buttonFlag = CommandManager.oscButtonMappings[self.keyString]
if buttonFlag != 0 {self.onScreenControls.releaseControllerButton(buttonFlag!)}
if self.keyString == "OSCL2" {self.onScreenControls.updateLeftTrigger(0x00)}
if self.keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0x00)}
}
if !OnScreenWidgetView.editMode && !self.keyString.contains("+") { // if the command(keystring contains "+", it's a multi-key command rather than a single key button
if CommandManager.mouseButtonMappings.keys.contains(self.keyString){
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), Int32(CommandManager.mouseButtonMappings[self.keyString]!))
}
if CommandManager.keyboardButtonMappings.keys.contains(self.keyString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[self.keyString]!,Int8(KEY_ACTION_UP), 0)
}
}
if OnScreenWidgetView.editMode { if OnScreenWidgetView.editMode {
guard let superview = superview else { return } guard let superview = superview else { return }
@@ -303,8 +303,8 @@ import UIKit
private func sendKeyboardCommand(_ cmd: RemoteCommand) { private func sendKeyboardCommand(_ cmd: RemoteCommand) {
print("Sending key-value") print("Sending key-value")
let keyboardCmdStrings = CommandManager.shared.extractKeyStrings(from: cmd.keyboardCmdString) let keyboardCmdStrings = CommandManager.shared.extractKeyStringsFromComboCommand(from: cmd.keyboardCmdString)
CommandManager.shared.sendKeyDownEventWithDelay(keyboardCmdStrings: keyboardCmdStrings!) CommandManager.shared.sendKeyComboCommand(keyboardCmdStrings: keyboardCmdStrings!)
} }
} }
@@ -362,13 +362,14 @@
NSString *cmdString = [alertController.textFields[0].text uppercaseString]; // convert to uppercase NSString *cmdString = [alertController.textFields[0].text uppercaseString]; // convert to uppercase
NSString *keyLabel = alertController.textFields[1].text; NSString *keyLabel = alertController.textFields[1].text;
if([keyLabel isEqualToString:@""]) keyLabel = [[cmdString lowercaseString] capitalizedString]; if([keyLabel isEqualToString:@""]) keyLabel = [[cmdString lowercaseString] capitalizedString];
bool noValidKeyboardString = [CommandManager.shared extractKeyStringsFrom:cmdString] == nil; // this is a invalid string. bool noValidKeyboardString = [CommandManager.shared extractKeyStringsFromComboCommandFrom:cmdString] == nil; // this is a invalid string.
bool noValidSuperComboButtonString = [CommandManager.shared extractKeyStringsFromComboKeysFrom:cmdString] == nil; // this is a invalid string.
bool noValidMouseButtonString = ![CommandManager.mouseButtonMappings.allKeys containsObject:cmdString]; bool noValidMouseButtonString = ![CommandManager.mouseButtonMappings.allKeys containsObject:cmdString];
bool noValidTouchPadString = ![CommandManager.touchPadCmds containsObject:cmdString]; bool noValidTouchPadString = ![CommandManager.touchPadCmds containsObject:cmdString];
bool noValidOscButtonString = ![CommandManager.oscButtonMappings.allKeys containsObject:cmdString]; bool noValidOscButtonString = ![CommandManager.oscButtonMappings.allKeys containsObject:cmdString];
bool noValidSpecialButtonString = ![CommandManager.specialOverlayButtonCmds containsObject:cmdString]; bool noValidSpecialButtonString = ![CommandManager.specialOverlayButtonCmds containsObject:cmdString];
if(noValidKeyboardString && noValidMouseButtonString && noValidTouchPadString && noValidOscButtonString && noValidSpecialButtonString) return; if(noValidKeyboardString && noValidMouseButtonString && noValidTouchPadString && noValidOscButtonString && noValidSpecialButtonString && noValidSuperComboButtonString) return;
//saving & present the keyboard button: //saving & present the keyboard button:
OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:cmdString keyLabel:keyLabel]; OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:cmdString keyLabel:keyLabel];