15

我正在使用CGEventTapCreateForPSN为我的应用程序捕获和过滤密钥。我对拦截其他应用程序的事件不感兴趣。我很确定事件点击对于我的目的来说太重了,但我一直无法找到更好的方法,并且使用事件点击有效。

具体来说,这段代码做了我想要的。

GetCurrentProcess(&psn);
CFMachPortRef eventTap = CGEventTapCreateForPSN(
    &psn,
    kCGHeadInsertEventTap,
    kCGEventTapOptionDefault,
    CGEventMaskBit(kCGEventKeyDown)
        | CGEventMaskBit(kCGEventKeyUp),
    eventCallback,
    userInfo);

而且我的回调处理得很好,事件仅从当前应用程序中截获。

不幸的是,从 10.9 开始,所有获取电流的方法ProcessSerialNumber都已被弃用。有一种旧的标准方法可以ProcessSerialNumber在同一进程中传递给其他例程,通过这个初始化......

ProcessSerialNumber psn = { 0, kCurrentProcess };

但这在调用时不起作用CGEventTapCreateForPSN。头文件 docs 表明了这一点,以下代码片段NULL作为确认返回。

ProcessSerialNumber psn = { 0, kCurrentProcess };
CFMachPortRef eventTap = CGEventTapCreateForPSN(
    &psn,
    kCGHeadInsertEventTap,
    kCGEventTapOptionDefault,
    CGEventMaskBit(kCGEventKeyDown)
        | CGEventMaskBit(kCGEventKeyUp),
    eventCallback,
    userInfo);

我可以使用CGEventTapCreate,但它会点击整个主机,然后我需要过滤任何未定向到我的应用程序的东西,而且它CGEventTapProxy是不透明的,我不知道如何使用它来确定它是否是我的应用程序。

我已经验证过不推荐使用的代码仍然有效,但 Apple 可以随时决定将其删除。那么,有没有人知道我应该如何继续调用CGEventTapCreateForPSN小牛队及其他球队?

谢谢!


更新

在 10.11(我认为那是 El Capitan)中,添加了一个新功能。虽然它的文档为零,但它的签名几乎与CGEventTapCreateForPSN.

CFMachPortRef CGEventTapCreateForPSN(
    void *processSerialNumber,
    CGEventTapPlacement place,
    CGEventTapOptions options,
    CGEventMask eventsOfInterest,
    CGEventTapCallBack callback,
    void *userInfo);

CFMachPortRef CGEventTapCreateForPid(
    pid_t pid,
    CGEventTapPlacement place,
    CGEventTapOptions options,
    CGEventMask eventsOfInterest,
    CGEventTapCallBack callback,
    void *userInfo);

因此,不需要弃用的函数,因为 PID 可以用作第一个参数。

4

2 回答 2

1

- (void)sendEvent:(NSEvent *)theEvent我认为您应该为此目的子类化 NSApplication 并覆盖方法。来自文档

您很少会发现真正需要创建自定义 NSApplication 子类。与一些面向对象的库不同,Cocoa 不需要您继承 NSApplication 来自定义应用程序行为。相反,它为您提供了许多其他方式来自定义应用程序。

还:

重要的

许多 AppKit 类依赖于 NSApplication 类,并且在此类完全初始化之前可能无法正常工作。因此,例如,您不应该尝试从 NSApplication 子类的初始化方法调用其他 AppKit 类的方法。

因此,您可以拦截通过您的应用程序传递的所有事件并调用自定义 NSApplicationDelegate 继承的协议方法。

// in SubApplication.h

@protocol ExtendedApplicationDelegate : NSApplicationDelegate

- (void)applicationDidTrapSomeInterestingEvent:(NSEvent *)event;

@end

// in SubApplication.m

- (void)sendEvent:(NSEvent *)event
{
    if ([event type] == NSKeyDown && [event keyCode]==_someCode)
    {
      // call application delegate method
    }
    [super sendEvent:event];
}

我不确定这种方法是否能解决问题,但您仍然可以尝试。

于 2015-05-20T14:06:18.843 回答
0

另一种方法是子类化NSApplication和覆盖nextEventMatchingMask:untilDate:inMode:dequeue:。这会看到通过覆盖看不到的鼠标事件sendEvent:,例如,在跟踪滚动条时。我不确定它是否对问题所涉及的键盘事件很重要,但其他偶然发现这个问题的人可能会感兴趣。

于 2018-08-28T22:04:20.953 回答