我正在研究如何在C中仅使用CoreFoundation
在其处理空间内实现OSX无GUI 命令行工具的key event捕获和回调, (没有Cocoa
,没有NSEvents
)。通过一些研究,我可以轻松地将此MCVE放在“全局级别”上(这需要以root特权运行该程序),但无法弄清楚该如何捕获和处理程序<仅。我也没有找到有关如何完成此操作的文档。我从SO的这一领域发现了一些问题,但所有问题都是基于Cocoa
API的。我很乐意提供所需的任何其他信息。
// gcc -Wall -o test test.c -framework ApplicationServices
// sudo test
#include <ApplicationServices/ApplicationServices.h>
CGEventRef testEventCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
printf( " Event Type: %d\n", type );
return event;
}
int main(int argc, char *argv[])
{
CFMachPortRef eventPort;
CFRunLoopSourceRef eventSrc;
CFRunLoopRef runLoop;
CGEventMask mask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp);
eventPort = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly,
mask,
testEventCallback,
NULL );
if ( eventPort == NULL ){
printf( "NULL eventPort\n" );
return 1;
}
eventSrc = CFMachPortCreateRunLoopSource(NULL, eventPort, 0);
if ( eventSrc == NULL ){
printf( "NULL eventSrc\n" );
return 1;
}
runLoop = CFRunLoopGetCurrent();
if ( runLoop == NULL ){
printf( "NULL runLoop\n" );
return 1;
}
CFRunLoopAddSource(runLoop, eventSrc, kCFRunLoopDefaultMode);
CFRunLoopRun();
return 0;
}
GetFrontProcess()
现在已被弃用,因此它使用NSWorkspace
来定位前端进程。let lock = DispatchQueue(label: "lock")
var events = [CGEvent]()
// track keyboard events using an event tap.
let callback: CGEventTapCallBack = { (tapProxy, eventType, event, _) -> Unmanaged<CGEvent>? in
// don't consume command keys.
if !event.flags.contains(.maskCommand) {
if eventType == .keyDown {
lock.sync {
events.append(event)
}
}
return nil
}
return Unmanaged<CGEvent>.passUnretained(event)
}
let eventMask = CGEventMask((1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.keyUp.rawValue))
if let frontmostProcess = NSWorkspace.shared.frontmostApplication?.processIdentifier, let eventTap = CGEvent.tapCreateForPid(pid: frontmostProcess, place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: eventMask, callback: callback, userInfo: nil) {
let source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, .commonModes)
CGEvent.tapEnable(tap: eventTap, enable: true)
CFRunLoopRun()
}