在 Swift 中如何使用 CGEventTapCreate?
How do you use CGEventTapCreate in Swift?
有没有人设法让这个功能在 Swift 中工作?
这是去年的参考 SO post:Using CGEventTapCreate Trouble with parameters in Swift
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
}
然后我用 unsafeBitCast(eventTapCallBackBlock, CGEventTapCallBack.self)
这样的回调参数调用了 CGEventTapCreate
我得到一个有效的 CFMachPortRef
返回,但是在 运行 时我在第一个事件中得到一个访问冲突异常。它会 "seem" 我接近 swift 在其当前发布状态下的解决方案。
使用 Xcode 版本 6.4
CGEventTapCreate()
的callback
参数是一个C函数指针,
在 Swift 1.x 中,不可能用 Swift 函数参数调用它。
然而,在Swift 2 (Xcode 7)中,接受函数指针参数的C函数
可以使用闭包或全局函数调用(限制是
闭包不得捕获其任何本地上下文)。
例如,这里是完整的翻译
Receiving, Filtering, and Modifying Key Presses and Releases
到 Swift:
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()
Swift3 的更新:
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()
有没有人设法让这个功能在 Swift 中工作?
这是去年的参考 SO post:Using CGEventTapCreate Trouble with parameters in Swift
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
}
然后我用 unsafeBitCast(eventTapCallBackBlock, CGEventTapCallBack.self)
我得到一个有效的 CFMachPortRef
返回,但是在 运行 时我在第一个事件中得到一个访问冲突异常。它会 "seem" 我接近 swift 在其当前发布状态下的解决方案。
使用 Xcode 版本 6.4
CGEventTapCreate()
的callback
参数是一个C函数指针,
在 Swift 1.x 中,不可能用 Swift 函数参数调用它。
然而,在Swift 2 (Xcode 7)中,接受函数指针参数的C函数 可以使用闭包或全局函数调用(限制是 闭包不得捕获其任何本地上下文)。
例如,这里是完整的翻译 Receiving, Filtering, and Modifying Key Presses and Releases 到 Swift:
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()
Swift3 的更新:
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()