2015-08-08 4 views
1

Неужели кому-то удалось заставить эту функцию работать в Swift?Как вы используете CGEventTapCreate в 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 
} 

Тогда у меня есть называемый CGEventTapCreate с параметром обратного вызова, например unsafeBitCast(eventTapCallBackBlock, CGEventTapCallBack.self)

Я получаю действительный CFMachPortRef назад, но во время выполнения я получаю исключение нарушения доступа при первом событии. «Казалось бы, я близок к быстрому решению в текущем состоянии выпуска.

Использование Xcode версии 6.4

ответ

15

Параметр CGEventTapCreate()callback является указателем на функцию С, и в Swift 1.x не представляется возможным назвать его с Swift аргумент функции.

Однако, функции C, которые принимают аргументы функции указателя , в Swift 2 (Xcode 7) может быть вызвана с помощью затворов или глобальные функции (с ограничением, что закрытие не должно захватить какой-либо из его локального контекста).

В качестве примера, вот полный перевод 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() 

Обновление для Swift 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 ... sigh ... по крайней мере, это возможно * – uchuugaka