模拟全局键盘按下

Llo*_*ish 1 macos keyboard-shortcuts swift swiftui

我正在 Mac 上构建一个 swiftUI 应用程序,我想知道是否有一种方法可以在应用程序运行时或在后台模拟键盘快捷键。我使用此应用程序的目标是当我的服务器向我发送相应的手势信息时调用快捷方式。我正在考虑使用,NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: self.handler)但我认为这更多的是重新编程快捷方式,而不仅仅是调用它们。

例如,如果我的服务器向我发送一个显示“粘贴”的字符串,那么无论我在哪个屏幕上,只要我的应用程序正在运行,我将如何调用命令粘贴快捷方式。任何帮助或信息将不胜感激!

Sam*_*Sam 5

我的 Mac 上有这个 Playground,所以我想我应该在这里分享它,以防它有帮助:

\n
import Cocoa\n\nlet src = CGEventSource(stateID: .hidSystemState)\n\nlet down = CGEvent(keyboardEventSource: src, virtualKey: 0x12, keyDown: true)!\nlet up = CGEvent(keyboardEventSource: src, virtualKey: 0x12, keyDown: false)!\n\nsleep(5)\n\n////down?.post(tap: .cghidEventTap)\n////up?.post(tap: .cghidEventTap)\n////down?.flags = .maskCommand\n//\n//let cmd_d = CGEvent(keyboardEventSource: src, virtualKey: 0x37, keyDown: true)!\n//let cmd_u = CGEvent(keyboardEventSource: src, virtualKey: 0x37, keyDown: false)!\n//let a_d = CGEvent(keyboardEventSource: src, virtualKey: 0x00, keyDown: true)!\n//let a_u = CGEvent(keyboardEventSource: src, virtualKey: 0x00, keyDown: false)!\n//let delete_d = CGEvent(keyboardEventSource: src, virtualKey: 0x33, keyDown: true)!\n//let delete_u = CGEvent(keyboardEventSource: src, virtualKey: 0x33, keyDown: false)!\n//\n//down.post(tap: .cghidEventTap)\n//up.post(tap: .cghidEventTap)\n//sleep(1)\n////cmd_d.post(tap: .cghidEventTap)\n//a_d.flags = .maskCommand\n//a_u.flags = .maskCommand\n//a_d.post(tap: .cghidEventTap)\n//a_u.post(tap: .cghidEventTap)\n////cmd_u.post(tap: .cghidEventTap)\n//sleep(1)\n//delete_d.post(tap: .cghidEventTap)\n//delete_u.post(tap: .cghidEventTap)\n\nenum KeyCode: UInt16 {\n    // https://gist.github.com/swillits/df648e87016772c7f7e5dbed2b345066\n\n    // Layout-independent Keys\n    // eg.These key codes are always the same key on all layouts.\n    case returnKey = 0x24\n//    case enter = 0x4C //0x24\n    case tab = 0x30\n    case space = 0x31\n    case delete = 0x33\n    case escape = 0x35\n    case command = 0x37\n    case shift = 0x38\n    case capsLock = 0x39\n    case option = 0x3A\n    case control = 0x3B\n    case rightShift = 0x3C\n    case rightOption = 0x3D\n    case rightControl = 0x3E\n    case leftArrow = 0x7B\n    case rightArrow = 0x7C\n    case downArrow = 0x7D\n    case upArrow = 0x7E\n    case volumeUp = 0x48\n    case volumeDown = 0x49\n    case mute = 0x4A\n    case help = 0x72\n    case home = 0x73\n    case pageUp = 0x74\n    case forwardDelete = 0x75\n    case end = 0x77\n    case pageDown = 0x79\n    case function = 0x3F\n    case f1 = 0x7A\n    case f2 = 0x78\n    case f4 = 0x76\n    case f5 = 0x60\n    case f6 = 0x61\n    case f7 = 0x62\n    case f3 = 0x63\n    case f8 = 0x64\n    case f9 = 0x65\n    case f10 = 0x6D\n    case f11 = 0x67\n    case f12 = 0x6F\n    case f13 = 0x69\n    case f14 = 0x6B\n    case f15 = 0x71\n    case f16 = 0x6A\n    case f17 = 0x40\n    case f18 = 0x4F\n    case f19 = 0x50\n    case f20 = 0x5A\n\n    // US-ANSI Keyboard Positions\n    // eg. These key codes are for the physical key (in any keyboard layout)\n    // at the location of the named key in the US-ANSI layout.\n    case a = 0x00\n    case b = 0x0B\n    case c = 0x08\n    case d = 0x02\n    case e = 0x0E\n    case f = 0x03\n    case g = 0x05\n    case h = 0x04\n    case i = 0x22\n    case j = 0x26\n    case k = 0x28\n    case l = 0x25\n    case m = 0x2E\n    case n = 0x2D\n    case o = 0x1F\n    case p = 0x23\n    case q = 0x0C\n    case r = 0x0F\n    case s = 0x01\n    case t = 0x11\n    case u = 0x20\n    case v = 0x09\n    case w = 0x0D\n    case x = 0x07\n    case y = 0x10\n    case z = 0x06\n\n    case zero = 0x1D\n    case one = 0x12\n    case two = 0x13\n    case three = 0x14\n    case four = 0x15\n    case five = 0x17\n    case six = 0x16\n    case seven = 0x1A\n    case eight = 0x1C\n    case nine = 0x19\n\n    case equals = 0x18\n    case minus = 0x1B\n    case semicolon = 0x29\n    case apostrophe = 0x27\n    case comma = 0x2B\n    case period = 0x2F\n    case forwardSlash = 0x2C\n    case backslash = 0x2A\n    case grave = 0x32\n    case leftBracket = 0x21\n    case rightBracket = 0x1E\n\n    case keypadDecimal = 0x41\n    case keypadMultiply = 0x43\n    case keypadPlus = 0x45\n    case keypadClear = 0x47\n    case keypadDivide = 0x4B\n    case keypadEnter = 0x4C\n    case keypadMinus = 0x4E\n    case keypadEquals = 0x51\n    case keypad0 = 0x52\n    case keypad1 = 0x53\n    case keypad2 = 0x54\n    case keypad3 = 0x55\n    case keypad4 = 0x56\n    case keypad5 = 0x57\n    case keypad6 = 0x58\n    case keypad7 = 0x59\n    case keypad8 = 0x5B\n    case keypad9 = 0x5C\n}\nfunc press(_ key: KeyCode, withModifiers modifiers: CGEventFlags = .init()) {\n    let down = CGEvent(keyboardEventSource: src, virtualKey: key.rawValue, keyDown: true)!\n    let up = CGEvent(keyboardEventSource: src, virtualKey: key.rawValue, keyDown: false)!\n    down.flags = modifiers\n    up.flags = modifiers\n    down.post(tap: .cghidEventTap)\n    up.post(tap: .cghidEventTap)\n}\nstruct KeyPress {\n    let key: KeyCode\n    let modifiers: CGEventFlags\n}\nfunc press(_ key: KeyPress) {\n    press(key.key, withModifiers: key.modifiers)\n}\n/// An enum representing possible typing rates.\n///\n/// - allAtOnce: All the text should be typed at once.\n/// - consistent: The text should be typed at a reasonable speed, but with no variance in delay.\n/// - natural: The text should be typed so that it appears natural.\n/// - customConsistent: The text should be typed at a consistent speed, specified by the associated value.\n/// - customVarying: The text should be typed around a given speed, with 5 possible ranges of variation. Both the base speed and the maximum variance are specified by associated values.\npublic enum Rate {\n    /// All the text should be typed at once.\n    case allAtOnce\n    /// The text should be typed at a reasonable speed, but with no variance in delay.\n    case consistent\n    /// The text should be typed so that it appears natural.\n    case natural\n    /// The text should be typed at a specified consistent speed.\n    /// - \xc2\xb5secondDelay: The delay between each key typed.\n    case customConsistent(\xc2\xb5secondDelay: UInt32)\n    /// The text should be typed around a specified given speed, with specified variation. The base delay should be the average delay time, and the max variance is the maximum distance from the average to the fastest/slowest possible delay.\n    /// - \xc2\xb5secondBaseDelay: The base delay between each key typed.\n    /// - maxVariance: The delay between each key typed.\n    case customVarying(\xc2\xb5secondBaseDelay: UInt32, maxVariance: UInt32)\n}\n\nfunc type(_ text: [KeyPress], typing: Rate = .natural) {\n    for character in text {\n        press(character)\n        switch typing {\n        case .allAtOnce:\n            usleep(0001000)\n        case .consistent:\n            usleep(0100000)\n        case .natural:\n            var sleepTime = UInt32.random(in: 0...4)\n            sleepTime *= 10000\n            usleep(0080000 + sleepTime)\n        case .customConsistent(let \xc2\xb5secondDelay):\n            usleep(\xc2\xb5secondDelay)\n        case let .customVarying(\xc2\xb5secondBaseDelay, maxVariance):\n            var sleepTime = UInt32.random(in: 0...4)\n            let base = \xc2\xb5secondBaseDelay - maxVariance\n            sleepTime *= (maxVariance / 2)\n            let \xc2\xb5secondDelay = base + sleepTime\n            usleep(\xc2\xb5secondDelay)\n        }\n    }\n}\nlet lowercaseCharMap: [Character: KeyCode] = [\n    "a": .a,\n    "b": .b,\n    "c": .c,\n    "d": .d,\n    "e": .e,\n    "f": .f,\n    "g": .g,\n    "h": .h,\n    "i": .i,\n    "j": .j,\n    "k": .k,\n    "l": .l,\n    "m": .m,\n    "n": .n,\n    "o": .o,\n    "p": .p,\n    "q": .q,\n    "r": .r,\n    "s": .s,\n    "t": .t,\n    "u": .u,\n    "v": .v,\n    "w": .w,\n    "x": .x,\n    "y": .y,\n    "z": .z,\n    "0": .zero,\n    "1": .one,\n    "2": .two,\n    "3": .three,\n    "4": .four,\n    "5": .five,\n    "6": .six,\n    "7": .seven,\n    "8": .eight,\n    "9": .nine,\n    "=": .equals,\n    "-": .minus,\n    ";": .semicolon,\n    "\'": .apostrophe,\n    ",": .comma,\n    ".": .period,\n    "/": .forwardSlash,\n    "\\\\": .backslash,\n    "`": .grave,\n    "[": .leftBracket,\n    "]": .rightBracket,\n    " ": .space\n]\nlet uppercaseCharMap: [Character: KeyCode] = [\n    "A": .a,\n    "B": .b,\n    "C": .c,\n    "D": .d,\n    "E": .e,\n    "F": .f,\n    "G": .g,\n    "H": .h,\n    "I": .i,\n    "J": .j,\n    "K": .k,\n    "L": .l,\n    "M": .m,\n    "N": .n,\n    "O": .o,\n    "P": .p,\n    "Q": .q,\n    "R": .r,\n    "S": .s,\n    "T": .t,\n    "U": .u,\n    "V": .v,\n    "W": .w,\n    "X": .x,\n    "Y": .y,\n    "Z": .z,\n    ")": .zero,\n    "!": .one,\n    "@": .two,\n    "#": .three,\n    "$": .four,\n    "%": .five,\n    "^": .six,\n    "&": .seven,\n    "*": .eight,\n    "(": .nine,\n    "+": .equals,\n    "_": .minus,\n    ":": .semicolon,\n    "\\"": .apostrophe,\n    "<": .comma,\n    ">": .period,\n    "?": .forwardSlash,\n    "|": .backslash,\n    "~": .grave,\n    "{": .leftBracket,\n    "}": .rightBracket,\n]\n\nfunc type(_ text: String, typing: Rate = .natural) {\n    type(str_to_kparr(text), typing: typing)\n}\n\ntype("Hello, there")\n\nfunc str_to_kparr(_ str: String) -> [KeyPress] {\n    str.map { char -> KeyPress in\n        if let kc = lowercaseCharMap[char] {\n            return KeyPress(key: kc, modifiers: .init())\n        }\n        if let kc = uppercaseCharMap[char] {\n            return KeyPress(key: kc, modifiers: .maskShift)\n        }\n        return KeyPress(key: .three, modifiers: .maskShift)\n    }\n}\n\nfunc +(lhs: String, rhs: [KeyPress]) -> [KeyPress] {\n    return str_to_kparr(lhs) + rhs\n}\nfunc +(lhs: [KeyPress], rhs: String) -> [KeyPress] {\n    return lhs + str_to_kparr(rhs)\n}\n\ntype("! General Kenobi" + [.init(key: .a, modifiers: .maskCommand), .init(key: .delete, modifiers: .init()), .init(key: .space, modifiers: [.maskCommand])])\n\nextension KeyPress {\n    static let returnKey = KeyPress(key: .returnKey, modifiers: .init())\n    static let enter = Self.returnKey\n    static let tab = KeyPress(key: .tab, modifiers: .init())\n    static let space = KeyPress(key: .space, modifiers: .init())\n    static let delete = KeyPress(key: .delete, modifiers: .init())\n    static let escape = KeyPress(key: .escape, modifiers: .init())\n    static let command = KeyPress(key: .command, modifiers: .init())\n    static let shift = KeyPress(key: .shift, modifiers: .init())\n    static let capsLock = KeyPress(key: .capsLock, modifiers: .init())\n    static let option = KeyPress(key: .option, modifiers: .init())\n    static let control = KeyPress(key: .control, modifiers: .init())\n    static let rightShift = KeyPress(key: .rightShift, modifiers: .init())\n    static let rightOption = KeyPress(key: .rightOption, modifiers: .init())\n    static let rightControl = KeyPress(key: .rightControl, modifiers: .init())\n    static let leftArrow = KeyPress(key: .leftArrow, modifiers: .init())\n    static let rightArrow = KeyPress(key: .rightArrow, modifiers: .init())\n    static let downArrow = KeyPress(key: .downArrow, modifiers: .init())\n    static let upArrow = KeyPress(key: .upArrow, modifiers: .init())\n    static let volumeUp = KeyPress(key: .volumeUp, modifiers: .init())\n    static let volumeDown = KeyPress(key: .volumeDown, modifiers: .init())\n    static let mute = KeyPress(key: .mute, modifiers: .init())\n    static let help = KeyPress(key: .help, modifiers: .init())\n    static let home = KeyPress(key: .home, modifiers: .init())\n    static let pageUp = KeyPress(key: .pageUp, modifiers: .init())\n    static let forwardDelete = KeyPress(key: .forwardDelete, modifiers: .init())\n    static let end = KeyPress(key: .end, modifiers: .init())\n    static let pageDown = KeyPress(key: .pageDown, modifiers: .init())\n    static let function = KeyPress(key: .function, modifiers: .init())\n    static let f1 = KeyPress(key: .f1, modifiers: .init())\n    static let f2 = KeyPress(key: .f2, modifiers: .init())\n    static let f4 = KeyPress(key: .f4, modifiers: .init())\n    static let f5 = KeyPress(key: .f5, modifiers: .init())\n    static let f6 = KeyPress(key: .f6, modifiers: .init())\n    static let f7 = KeyPress(key: .f7, modifiers: .init())\n    static let f3 = KeyPress(key: .f3, modifiers: .init())\n    static let f8 = KeyPress(key: .f8, modifiers: .init())\n    static let f9 = KeyPress(key: .f9, modifiers: .init())\n    static let f10 = KeyPress(key: .f10, modifiers: .init())\n    static let f11 = KeyPress(key: .f11, modifiers: .init())\n    static let f12 = KeyPress(key: .f12, modifiers: .init())\n    static let f13 = KeyPress(key: .f13, modifiers: .init())\n    static let f14 = KeyPress(key: .f14, modifiers: .init())\n    static let f15 = KeyPress(key: .f15, modifiers: .init())\n    static let f16 = KeyPress(key: .f16, modifiers: .init())\n    static let f17 = KeyPress(key: .f17, modifiers: .init())\n    static let f18 = KeyPress(key: .f18, modifiers: .init())\n    static let f19 = KeyPress(key: .f19, modifiers: .init())\n    static let f20 = KeyPress(key: .f20, modifiers: .init())\n\n        // US-ANSI Keyboard Positions\n        // eg. These key codes are for the physical key (in any keyboard layout)\n        // at the location of the named key in the US-ANSI layout.\n    static let a = KeyPress(key: .a, modifiers: .init())\n    static let b = KeyPress(key: .b, modifiers: .init())\n    static let c = KeyPress(key: .c, modifiers: .init())\n    static let d = KeyPress(key: .d, modifiers: .init())\n    static let e = KeyPress(key: .e, modifiers: .init())\n    static let f = KeyPress(key: .f, modifiers: .init())\n    static let g = KeyPress(key: .g, modifiers: .init())\n    static let h = KeyPress(key: .h, modifiers: .init())\n    static let i = KeyPress(key: .i, modifiers: .init())\n    static let j = KeyPress(key: .j, modifiers: .init())\n    static let k = KeyPress(key: .k, modifiers: .init())\n    static let l = KeyPress(key: .l, modifiers: .init())\n    static let m = KeyPress(key: .m, modifiers: .init())\n    static let n = KeyPress(key: .n, modifiers: .init())\n    static let o = KeyPress(key: .o, modifiers: .init())\n    static let p = KeyPress(key: .p, modifiers: .init())\n    static let q = KeyPress(key: .q, modifiers: .init())\n    static let r = KeyPress(key: .r, modifiers: .init())\n    static let s = KeyPress(key: .s, modifiers: .init())\n    static let t = KeyPress(key: .t, modifiers: .init())\n    static let u = KeyPress(key: .u, modifiers: .init())\n    static let v = KeyPress(key: .v, modifiers: .init())\n    static let w = KeyPress(key: .w, modifiers: .init())\n    static let x = KeyPress(key: .x, modifiers: .init())\n    static let y = KeyPress(key: .y, modifiers: .init())\n    static let z = KeyPress(key: .z, modifiers: .init())\n    static let A = KeyPress(key: .a, modifiers: .maskShift)\n    static let B = KeyPress(key: .b, modifiers: .maskShift)\n    static let C = KeyPress(key: .c, modifiers: .maskShift)\n    static let D = KeyPress(key: .d, modifiers: .maskShift)\n    static let E = KeyPress(key: .e, modifiers: .maskShift)\n    static let F = KeyPress(key: .f, modifiers: .maskShift)\n    static let G = KeyPress(key: .g, modifiers: .maskShift)\n    static let H = KeyPress(key: .h, modifiers: .maskShift)\n    static let I = KeyPress(key: .i, modifiers: .maskShift)\n    static let J = KeyPress(key: .j, modifiers: .maskShift)\n    static let K = KeyPress(key: .k, modifiers: .maskShift)\n    static let L = KeyPress(key: .l, modifiers: .maskShift)\n    static let M = KeyPress(key: .m, modifiers: .maskShift)\n    static let N = KeyPress(key: .n, modifiers: .maskShift)\n    static let O = KeyPress(key: .o, modifiers: .maskShift)\n    static let P = KeyPress(key: .p, modifiers: .maskShift)\n    static let Q = KeyPress(key: .q, modifiers: .maskShift)\n    static let R = KeyPress(key: .r, modifiers: .maskShift)\n    static let S = KeyPress(key: .s, modifiers: .maskShift)\n    static let T = KeyPress(key: .t, modifiers: .maskShift)\n    static let U = KeyPress(key: .u, modifiers: .maskShift)\n    static let V = KeyPress(key: .v, modifiers: .maskShift)\n    static let W = KeyPress(key: .w, modifiers: .maskShift)\n    static let X = KeyPress(key: .x, modifiers: .maskShift)\n    static let Y = KeyPress(key: .y, modifiers: .maskShift)\n    static let Z = KeyPress(key: .z, modifiers: .maskShift)\n\n    static let zero = KeyPress(key: .zero, modifiers: .init())\n    static let one = KeyPress(key: .one, modifiers: .init())\n    static let two = KeyPress(key: .two, modifiers: .init())\n    static let three = KeyPress(key: .three, modifiers: .init())\n    static let four = KeyPress(key: .four, modifiers: .init())\n    static let five = KeyPress(key: .five, modifiers: .init())\n    static let six = KeyPress(key: .six, modifiers: .init())\n    static let seven = KeyPress(key: .seven, modifiers: .init())\n    static let eight = KeyPress(key: .eight, modifiers: .init())\n    static let nine = KeyPress(key: .nine, modifiers: .init())\n    static let leftParenthesis = KeyPress(key: .zero, modifiers: .maskShift)\n    static let exclamationPoint = KeyPress(key: .one, modifiers: .maskShift)\n    static let atSign = KeyPress(key: .two, modifiers: .maskShift)\n    static let numberSign = KeyPress(key: .three, modifiers: .maskShift)\n    static let dollarSign = KeyPress(key: .four, modifiers: .maskShift)\n    static let percent = KeyPress(key: .five, modifiers: .maskShift)\n    static let caret = KeyPress(key: .six, modifiers: .maskShift)\n    static let ampersand = KeyPress(key: .seven, modifiers: .maskShift)\n    static let asterisk = KeyPress(key: .eight, modifiers: .maskShift)\n    static let rightParenthesis = KeyPress(key: .nine, modifiers: .maskShift)\n\n    static let equals = KeyPress(key: .equals, modifiers: .init())\n    static let minus = KeyPress(key: .minus, modifiers: .init())\n    static let semicolon = KeyPress(key: .semicolon, modifiers: .init())\n    static let apostrophe = KeyPress(key: .apostrophe, modifiers: .init())\n    static let comma = KeyPress(key: .comma, modifiers: .init())\n    static let period = KeyPress(key: .period, modifiers: .init())\n    static let forwardSlash = KeyPress(key: .forwardSlash, modifiers: .init())\n    static let backslash = KeyPress(key: .backslash, modifiers: .init())\n    static let grave = KeyPress(key: .grave, modifiers: .init())\n    static let leftBracket = KeyPress(key: .leftBracket, modifiers: .init())\n    static let rightBracket = KeyPress(key: .rightBracket, modifiers: .init())\n    static let plus = KeyPress(key: .equals, modifiers: .maskShift)\n    static let underscore = KeyPress(key: .minus, modifiers: .maskShift)\n    static let colon = KeyPress(key: .semicolon, modifiers: .maskShift)\n    static let quotationMark = KeyPress(key: .apostrophe, modifiers: .maskShift)\n    static let lessThan = KeyPress(key: .comma, modifiers: .maskShift)\n    static let greaterThan = KeyPress(key: .period, modifiers: .maskShift)\n    static let questionMark = KeyPress(key: .forwardSlash, modifiers: .maskShift)\n    static let pipe = KeyPress(key: .backslash, modifiers: .maskShift)\n    static let tilde = KeyPress(key: .grave, modifiers: .maskShift)\n    static let leftBrace = KeyPress(key: .leftBracket, modifiers: .maskShift)\n    static let rightBrace = KeyPress(key: .rightBracket, modifiers: .maskShift)\n\n    static let keypadDecimal = KeyPress(key: .keypadDecimal, modifiers: .init())\n    static let keypadMultiply = KeyPress(key: .keypadMultiply, modifiers: .init())\n    static let keypadPlus = KeyPress(key: .keypadPlus, modifiers: .init())\n    static let keypadClear = KeyPress(key: .keypadClear, modifiers: .init())\n    static let keypadDivide = KeyPress(key: .keypadDivide, modifiers: .init())\n    static let keypadEnter = KeyPress(key: .keypadEnter, modifiers: .init())\n    static let keypadMinus = KeyPress(key: .keypadMinus, modifiers: .init())\n    static let keypadEquals = KeyPress(key: .keypadEquals, modifiers: .init())\n    static let keypad0 = KeyPress(key: .keypad0, modifiers: .init())\n    static let keypad1 = KeyPress(key: .