你如何在Swift中使用CGEventTapCreate?

时间:2015-08-08 07:59:04

标签: swift macos core-graphics cgeventtap

有没有人设法让这个功能在Swift中运行?

以下是去年的参考SO帖子:Using CGEventTapCreate Trouble with parameters in Swift

Apple Doc: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
}

然后我用C unsafeBitCast(eventTapCallBackBlock, CGEventTapCallBack.self)等回调参数调用CGEventTapCreate

我得到了有效的CFMachPortRef,但是在运行时我在第一个事件上遇到了访问冲突异常。它似乎“似乎”我在当前的释放状态下接近快速解决方案。

使用Xcode版本6.4

1 个答案:

答案 0 :(得分:20)

callback的{​​{1}}参数是C函数指针, 并且在 Swift 1.x 中,不可能使用Swift函数参数调用它。

但是,在 Swift 2 (Xcode 7)中,C函数接受函数指针参数 可以使用闭包或全局函数调用(具有限制 闭包不得捕获任何本地语境。)

举个例子,这是一个完整的翻译 Receiving, Filtering, and Modifying Key Presses and Releases 到斯威夫特:

CGEventTapCreate()

更新 Swift 3:

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()