import Foundation public struct HIDKeyMapping: Equatable, Hashable { public let source: UInt64 public let destination: UInt64 public init(source: UInt64, destination: UInt64) { self.source = source self.destination = destination } } public enum HIDMappingCodecError: Error, Equatable { case unrecognizedOutput case invalidEntry } // Parse OpenStep-style hidutil --get output. Unknown entries are rejected // rather than risking deletion of someone else's keyboard remappings. public enum HIDMappingCodec { public static let capsUsage: UInt64 = 0x700000039 public static let f19Usage: UInt64 = 0x70000006E public static let capsToF19 = HIDKeyMapping( source: capsUsage, destination: f19Usage ) public static func parse(_ output: String) throws -> [HIDKeyMapping] { var value = output.trimmingCharacters(in: .whitespacesAndNewlines) if value.hasPrefix("UserKeyMapping:") { value = String(value.dropFirst("UserKeyMapping:".count)) .trimmingCharacters(in: .whitespacesAndNewlines) } guard value.first == "(", value.last == ")" else { throw HIDMappingCodecError.unrecognizedOutput } let inner = String(value.dropFirst().dropLast()) .trimmingCharacters(in: .whitespacesAndNewlines) if inner.isEmpty || inner == "null" { return [] } let entryPattern = try NSRegularExpression(pattern: #"\{([^{}]*)\}"#) let matches = entryPattern.matches( in: inner, range: NSRange(inner.startIndex.. String { let entries: [[String: NSNumber]] = mappings.map { [ "HIDKeyboardModifierMappingSrc": NSNumber(value: $0.source), "HIDKeyboardModifierMappingDst": NSNumber(value: $0.destination), ] } let data = try JSONSerialization.data( withJSONObject: ["UserKeyMapping": entries], options: [.sortedKeys] ) return String(decoding: data, as: UTF8.self) } private static func parseEntry(_ body: String) throws -> HIDKeyMapping { let fieldPattern = try NSRegularExpression( pattern: #"([A-Za-z][A-Za-z0-9_]*)\s*=\s*([^;]+);"# ) let matches = fieldPattern.matches( in: body, range: NSRange(body.startIndex..