153 lines
5.1 KiB
Swift
153 lines
5.1 KiB
Swift
//
|
|
// KeyManager.swift
|
|
// Moonlight-ZWM
|
|
//
|
|
// Created by ZWM on 2024/7/23.
|
|
// Copyright © 2024 Moonlight Game Streaming Project. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
// Define the RemoteCommand class
|
|
@objc public class RemoteCommand: NSObject, NSSecureCoding {
|
|
// MARK: - NSSecureCoding
|
|
|
|
public static var supportsSecureCoding: Bool {
|
|
return true
|
|
}
|
|
|
|
// MARK: - Properties
|
|
|
|
@objc var keyboardCmdString: String
|
|
@objc var alias: String
|
|
|
|
// MARK: - Initialization
|
|
|
|
init(keyboardCmdString: String, alias: String) {
|
|
self.keyboardCmdString = keyboardCmdString
|
|
self.alias = alias
|
|
}
|
|
|
|
// MARK: - NSSecureCoding
|
|
|
|
required public init?(coder: NSCoder) {
|
|
guard let keyboardCmdString = coder.decodeObject(of: NSString.self, forKey: "keyboardCmdString") as String?,
|
|
let alias = coder.decodeObject(of: NSString.self, forKey: "alias") as String? else {
|
|
return nil
|
|
}
|
|
self.keyboardCmdString = keyboardCmdString
|
|
self.alias = alias
|
|
}
|
|
|
|
public func encode(with coder: NSCoder) {
|
|
coder.encode(keyboardCmdString, forKey: "keyboardCmdString")
|
|
coder.encode(alias, forKey: "alias")
|
|
}
|
|
}
|
|
|
|
|
|
// Define the CommandManager class
|
|
@objc public class CommandManager: NSObject {
|
|
@objc public static let shared = CommandManager()
|
|
|
|
static let keyMappings: [String: UInt16] = [
|
|
"CTRL": 0x11,
|
|
"ALT": 0x12,
|
|
"DEL": 0x2E,
|
|
"F1": 0x70,
|
|
"F2": 0x71
|
|
]
|
|
|
|
private var commands: [RemoteCommand] = []
|
|
|
|
public weak var viewController: CommandManagerViewController?
|
|
|
|
private override init() {
|
|
super.init()
|
|
loadCommands()
|
|
}
|
|
|
|
@objc public func createTestKeyMappings() -> [String: UInt16] {
|
|
return CommandManager.keyMappings
|
|
}
|
|
|
|
// extractKeyStrings from keyboardCMDString
|
|
@objc public func extractKeyStrings(from input: String) -> [String]? {
|
|
let keys = CommandManager.keyMappings.keys.joined(separator: "|")
|
|
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
|
|
}
|
|
|
|
for (index, key) in keyStrings.enumerated() {
|
|
print("Key \(index): \(key)")
|
|
}
|
|
|
|
return keyStrings
|
|
}
|
|
|
|
@objc public func addCommand(_ command: RemoteCommand) {
|
|
command.keyboardCmdString = command.keyboardCmdString.uppercased() // convert all letters to upper case
|
|
let keyStrings = extractKeyStrings(from: command.keyboardCmdString)
|
|
if (keyStrings == nil) {return} // in case of non-keyboard command strings, return
|
|
commands.append(command)
|
|
saveCommands()
|
|
viewController?.reloadTableView() // don't know why but this reload has to be called from the CommandManager, doesn't work by calling it in the viewcontroller, probably related with the dialog box.
|
|
}
|
|
|
|
@objc public func deleteCommand(at index: Int) {
|
|
guard index >= 0 && index < commands.count else {
|
|
return
|
|
}
|
|
commands.remove(at: index)
|
|
saveCommands()
|
|
}
|
|
|
|
@objc public func getAllCommands() -> [RemoteCommand] {
|
|
return commands
|
|
}
|
|
|
|
private func loadCommands() {
|
|
if let savedCommandsData = UserDefaults.standard.data(forKey: "savedCommands") {
|
|
do {
|
|
// Attempt to unarchive the data into an array of RemoteCommand
|
|
if let savedCommands = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, RemoteCommand.self], from: savedCommandsData) as? [RemoteCommand] {
|
|
// Assign the unarchived commands to your property
|
|
print(" Assign the unarchived commands to your property ")
|
|
commands = savedCommands
|
|
} else {
|
|
// Handle the case where the data could not be unarchived into the expected type
|
|
print("Data could not be unarchived into [RemoteCommand]")
|
|
}
|
|
} catch {
|
|
// Handle any errors that occur during unarchiving
|
|
print("Failed to unarchive savedCommands with error: \(error)")
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private func saveCommands() {
|
|
if let data = try? NSKeyedArchiver.archivedData(withRootObject: commands, requiringSecureCoding: false) {
|
|
UserDefaults.standard.set(data, forKey: "savedCommands")
|
|
}
|
|
}
|
|
}
|