Simular keypress usando Swift

Estou procurando uma maneira de simular pressionamentos de teclas no OSX. Eu encontrei outra solução ( Simular keypress para teclas de atalho do sistema ) usando Objective-C, mas eu preciso fazer isso com Swift. Como posso adaptar o CGEventCreateKeyboardEvent?

O código nessa resposta vinculada é facilmente convertível em código Swift, no entanto, há um punhado de dicas que você precisará resolver ao longo do caminho:

CGEventSourceCreate usa um CGEventSourceStateID , que é uma typealiase para um UInt32 , mas as constantes como kCGEventSourceStateHIDSystemState são definidas como Int , portanto, será necessário CGEventSourceStateID(kCGEventSourceStateHIDSystemState) las, por exemplo, CGEventSourceStateID(kCGEventSourceStateHIDSystemState) . Da mesma forma com CGEventFlags .

CGEventSourceCreate e CGEventCreateKeyboardEvent retornam um Unmanaged Unmanaged (ou não Unmanaged ). A API Swift gerada automaticamente para o Core Graphics não sabe se os objects retornados precisam ser liberados por você ou não, portanto, é necessário verificar os documentos da API para essas chamadas e usar takeRetainedValue() ou takeUnretainedValue() adequadamente no retorno valor, para convertê-los no tipo subjacente com o qual você deseja trabalhar.

Finalmente, eles retornam opções implicitamente não-desembrulhadas, então você precisa decidir se quer checar por nils ou apenas viver com a emoção de explosões em tempo de execução se eles retornarem um.

Dado que é muito simples transformar o Objective-C nessa resposta demonstrando pressionar Cmd-Space para Swift, eu apenas tentei colar isso em um aplicativo de rascunho e funcionou bem:

(embora eu não tenha verificado os documentos da API para saber se a retenção é a coisa correta a fazer ou não)

 let src = CGEventSourceCreate(CGEventSourceStateID(kCGEventSourceStateHIDSystemState)).takeRetainedValue() let cmdd = CGEventCreateKeyboardEvent(src, 0x38, true).takeRetainedValue() let cmdu = CGEventCreateKeyboardEvent(src, 0x38, false).takeRetainedValue() let spcd = CGEventCreateKeyboardEvent(src, 0x31, true).takeRetainedValue() let spcu = CGEventCreateKeyboardEvent(src, 0x31, false).takeRetainedValue() CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand)); CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand)); let loc = CGEventTapLocation(kCGHIDEventTap) CGEventPost(loc, cmdd) CGEventPost(loc, spcd) CGEventPost(loc, spcu) CGEventPost(loc, cmdu) 

Trabalhando com o Swift 3

 let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState) let cmdd = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: true) let cmdu = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: false) let spcd = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: true) let spcu = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: false) spcd?.flags = CGEventFlags.maskCommand; let loc = CGEventTapLocation.cghidEventTap cmdd?.post(tap: loc) spcd?.post(tap: loc) spcu?.post(tap: loc) cmdu?.post(tap: loc) 

Swift 3

Para mim, os valores de chave hexadecimais como: 0x124 não funcionaram, mas o simples UInt 124 fez o truque!

Uma boa coleção de códigos de teclas pode ser encontrada aqui ! Este snippet de código copiar e colar simula um pressionamento de tecla da seta para a direita. Altere o número da chave para o que você deseja simular:

  // Simulate Right Arrow keypress let rightArrowKeyCode: UInt16 = 124 let keyDownEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: true) keyDownEvent?.flags = CGEventFlags.maskCommand keyDownEvent?.post(tap: CGEventTapLocation.cghidEventTap) let keyUpEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: false) keyUpEvent?.flags = CGEventFlags.maskCommand keyUpEvent?.post(tap: CGEventTapLocation.cghidEventTap) 

Fiz isso para um projeto do Swift 4, não se esqueça de que o sandboxing do aplicativo não permitirá que um aplicativo envie pressionamentos de teclas como este, para que ele precise ser desativado. Isso significa que seu aplicativo seria proibido na AppStore.

 import Foundation class FakeKey { static func send(_ keyCode: CGKeyCode, useCommandFlag: Bool) { let sourceRef = CGEventSource(stateID: .combinedSessionState) if sourceRef == nil { NSLog("FakeKey: No event source") return } let keyDownEvent = CGEvent(keyboardEventSource: sourceRef, virtualKey: keyCode, keyDown: true) if useCommandFlag { keyDownEvent?.flags = .maskCommand } let keyUpEvent = CGEvent(keyboardEventSource: sourceRef, virtualKey: keyCode, keyDown: false) keyDownEvent?.post(tap: .cghidEventTap) keyUpEvent?.post(tap: .cghidEventTap) } }