2015-02-02 8 views
33

Sto provando ad avere un gestore nella mia app per Mac OS X scritto in Swift per un combo globale (a livello di sistema), ma non riesco a trovare la documentazione adeguata per questo. Ho letto che avrei dovuto gironzolare con le vecchie API Carbon per questo, non c'è modo migliore? Puoi mostrarmi qualche prova del codice Swift? Grazie in anticipo!Come ascoltare i tasti di scelta rapida globali con Swift in un'app di OS X?

+0

Che cosa hai provato esattamente? Cosa intendi con i tasti di scelta rapida? Hai provato il monitor globale NSEvent o CGEventTap – uchuugaka

risposta

10

Da Swift 2.0, è ora possibile passare un puntatore di funzione alle API C.

var gMyHotKeyID = EventHotKeyID() 
    gMyHotKeyID.signature = OSType("swat".fourCharCodeValue) 
    gMyHotKeyID.id = UInt32(keyCode) 

    var eventType = EventTypeSpec() 
    eventType.eventClass = OSType(kEventClassKeyboard) 
    eventType.eventKind = OSType(kEventHotKeyPressed) 

    // Install handler. 
    InstallEventHandler(GetApplicationEventTarget(), {(nextHanlder, theEvent, userData) -> OSStatus in 
      var hkCom = EventHotKeyID() 
      GetEventParameter(theEvent, EventParamName(kEventParamDirectObject), EventParamType(typeEventHotKeyID), nil, sizeof(EventHotKeyID), nil, &hkCom) 

      /// Check that hkCom in indeed your hotkey ID and handle it. 
     }, 1, &eventType, nil, nil) 

    // Register hotkey. 
    let status = RegisterEventHotKey(UInt32(keyCode), UInt32(modifierKeys), gMyHotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef) 
+0

Non funziona in 'Swift 4' e senza una spiegazione più dettagliata è impossibile da implementare. – ixany

+0

Funziona bene in Swift 4, ho convertito i miei progetti in Swift 4 e funziona perfettamente. Come sviluppatore, dovresti sapere che "non funziona" è la peggiore descrizione possibile di un problema - che cosa significa "non funziona"? Non viene compilato? Che errore di compilazione stai ottenendo? Non c'è davvero molto da spiegare - ogni funzione utilizzata è documentata da Apple. –

+0

Solo buone vibrazioni, Charlie! Sarebbe bello poter condividere anche la tua soluzione Swift 4. La soluzione che hai postato è incompleta e ciò rende difficile adattarsi ai principianti. Una cosa che sarebbe utile dire è che è necessario importare 'Carbon'. Il prossimo problema che ho affrontato è che 'String' non ha una proprietà' .fourCharCodeValue'. Sarebbe anche bello poter fornire un esempio per 'keyCode' e' modifierKeys'. – ixany

10

Non credo che tu possa farlo al 100% Swift oggi. Avrai bisogno di chiamare InstallEventHandler() o CGEventTapCreate(), ed entrambi richiedono uno CFunctionPointer, che non può essere creato in Swift. Il tuo piano migliore è quello di utilizzare soluzioni ObjC consolidate come DDHotKey e bridge to Swift.

Si può provare a utilizzare NSEvent.addGlobalMonitorForEventsMatchingMask(handler:), ma solo le copie degli eventi. Non puoi consumarli. Ciò significa che il tasto di scelta rapida verrà inoltrato anche all'app attualmente attiva, che può causare problemi. Ecco un esempio, ma raccomando l'approccio ObjC; quasi certamente funzionerà meglio.

let keycode = UInt16(kVK_ANSI_X) 
let keymask: NSEventModifierFlags = .CommandKeyMask | .AlternateKeyMask | .ControlKeyMask 

func handler(event: NSEvent!) { 
    if event.keyCode == self.keycode && 
     event.modifierFlags & self.keymask == self.keymask { 
      println("PRESSED") 
    } 
} 

// ... to set it up ... 
    let options = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionaryRef 
    let trusted = AXIsProcessTrustedWithOptions(options) 
    if (trusted) { 
     NSEvent.addGlobalMonitorForEventsMatchingMask(.KeyDownMask, handler: self.handler) 
    } 

Ciò richiede anche che i servizi di accessibilità siano approvati per questa app. Inoltre, non cattura gli eventi inviati alla propria applicazione, quindi è necessario catturarli con la catena di risposta, il nostro uso è addLocalMointorForEventsMatchingMask(handler:) per aggiungere un gestore locale.

+0

Anche se è utilizzabile, è importante ricordare che l'utente sta concedendo alla tua app la possibilità di monitorare ogni singolo tratto chiave, che è potenzialmente pericoloso, soprattutto se l'app non è sandbox e può essere iniettata . La vecchia API Carbon farà ciò solo per le combinazioni definite dall'utente, rendendole una soluzione "più sicura". –

6

Un rapido Swift 3 aggiornamento per la messa a punto:

let opts = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionary 

    guard AXIsProcessTrustedWithOptions(opts) == true else { return } 

    NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: self.handler) 
+0

Nota: l'API Hotkey basata su carbone non ha bisogno di privilegi di accesso (non può essere sul Mac App Store), anche se questo è sicuramente più semplice da implementare. – ctietze

+0

Ci sono app come CopyLess 2 che ascoltano keyDown e non richiedono accessibilità, ne sai qualcosa? Forse le app del negozio non lo richiedono? –

0

Date un'occhiata alla Biblioteca tasto di scelta rapida. Puoi semplicemente usare Carthage per implementarlo nella tua app. HotKey Library

Problemi correlati