2015-08-08 73 views
1

有沒有人設法讓這個函數在Swift中工作?你如何在Swift中使用CGEventTapCreate?

這裏是參考去年SO發佈:Using CGEventTapCreate Trouble with parameters in Swift

蘋果文檔:https://developer.apple.com/library/prerelease/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/func/CGEventTapCreate

這裏是CGEventTapCallBack是如何定義的:

typealias CGEventTapCallBack = CFunctionPointer<((CGEventTapProxy, CGEventType, CGEvent!, UnsafeMutablePointer<Void>) -> Unmanaged<CGEvent>!)> 

下面是我寫的塊:

let eventTapCallBackBlock : @objc_block 
(CGEventTapProxy, CGEventType, CGEventRef, UnsafeMutablePointer<Void>) -> CGEventRef = 
{ (eventTapProxy: CGEventTapProxy, eventType: CGEventType, event: CGEventRef, refcon: UnsafeMutablePointer<Void>) in 
    return event 
} 

然後我使用回調參數調用CGEventTapCreate,例如unsafeBitCast(eventTapCallBackBlock, CGEventTapCallBack.self)

回到頂部我得到了一個有效的CFMachPortRef,但在運行時,第一個事件發生訪問衝突異常。它會「看起來」我在當前版本狀態下快速接近解決方案。

使用的Xcode版本6.4

回答

15

CGEventTapCreate()callback參數是一個C函數指針, 和在夫特1.x中這是不可能用夫特函數參數調用它。

然而,在夫特2(Xcode的7),其採取函數指針參數,C功能 可以使用閉包或全局函數(條件是 閉合不能捕獲任何其本地上下文的限制)被調用。

作爲一個例子,這裏是 Receiving, Filtering, and Modifying Key Presses and Releases 斯威夫特一個完整的翻譯:

import Foundation 

func myCGEventCallback(proxy : CGEventTapProxy, type : CGEventType, event : CGEvent, refcon : UnsafeMutablePointer<Void>) -> Unmanaged<CGEvent>? { 

    if [.KeyDown , .KeyUp].contains(type) { 
     var keyCode = CGEventGetIntegerValueField(event, .KeyboardEventKeycode) 
     if keyCode == 0 { 
      keyCode = 6 
     } else if keyCode == 6 { 
      keyCode = 0 
     } 
     CGEventSetIntegerValueField(event, .KeyboardEventKeycode, keyCode) 
    } 
    return Unmanaged.passRetained(event) 
} 

let eventMask = (1 << CGEventType.KeyDown.rawValue) | (1 << CGEventType.KeyUp.rawValue) 
guard let eventTap = CGEventTapCreate(.CGSessionEventTap, 
    .HeadInsertEventTap, 
    .Default, 
    CGEventMask(eventMask), 
    myCGEventCallback, 
    nil) else { 
     print("failed to create event tap") 
     exit(1) 
} 

let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0) 
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes) 
CGEventTapEnable(eventTap, true) 
CFRunLoopRun() 

更新斯威夫特3:

import Foundation 

func myCGEventCallback(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, refcon: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? { 

    if [.keyDown , .keyUp].contains(type) { 
     var keyCode = event.getIntegerValueField(.keyboardEventKeycode) 
     if keyCode == 0 { 
      keyCode = 6 
     } else if keyCode == 6 { 
      keyCode = 0 
     } 
     event.setIntegerValueField(.keyboardEventKeycode, value: keyCode) 
    } 
    return Unmanaged.passRetained(event) 
} 

let eventMask = (1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.keyUp.rawValue) 
guard let eventTap = CGEvent.tapCreate(tap: .cgSessionEventTap, 
             place: .headInsertEventTap, 
             options: .defaultTap, 
             eventsOfInterest: CGEventMask(eventMask), 
             callback: myCGEventCallback, 
             userInfo: nil) else { 
             print("failed to create event tap") 
             exit(1) 
} 

let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0) 
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes) 
CGEvent.tapEnable(tap: eventTap, enable: true) 
CFRunLoopRun() 
+0

感謝您的答覆。有沒有與@objc_blocks的任何經驗來解決這種情況? – chrisp

+0

@jacobsd:CGEventTapCreate()將C函數指針作爲參數,而不是Objective-C塊。我不認爲你可以用Swift 1.2(Xcode 6.4)回調來解決這個問題。 –

+2

Holy Heck,比C/Objective-C版本更醜陋...感嘆...至少它是*可能的* – uchuugaka