小牛队中的CGEventTapCreateForPSN +(不推荐使用GetCurrentProcess)

时间:2015-04-02 01:57:54

标签: macos cocoa osx-mavericks osx-yosemite cgeventtap

我正在使用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可以用作第一个参数。

2 个答案:

答案 0 :(得分:1)

我认为你应该为NSApplication创建子类并覆盖- (void)sendEvent:(NSEvent *)theEvent方法。 来自docs

  

您很少发现真正需要创建自定义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];
}

我不确定这种方法是否解决了这个问题,但你还是试一试。

答案 1 :(得分:0)

另一种方法是继承df1 <- read.table(text = "Symbol MCL1 ABCB1 BAX IKZF1 WWOX BCL2L1 BCL2L11 CCND1 TNFSF10", header = T) df2 <- read.table(text = "Symbol2 Aliases MCL1 'MCL1, BCL2 family apoptosis regulator' ABCB1 'ATP binding cassette subfamily B member 1' WWOX 'WW domain containing oxidoreductase' BCL2L1 'RB transcriptional corepressor 1' BOK 'peroxisome proliferator activated receptor gamma' RHOA 'ras homolog family member A' ABCC1 'C-X-C motif chemokine ligand 12' PARP1 'poly(ADP-ribose) polymerase 1' BAK1 'BRCA1, DNA repair associated'", header = T) df3 <- read.table(text = "description OMIM Aliases 'MCL1, BCL2 family apoptosis regulator' 159552 'G protein subunit alpha 12' 'ATP binding cassette subfamily B member 1' 171050 'matrix metallopeptidase 9' 'BCL2 associated X, apoptosis regulator' 600040 'cadherin 1' 'IKAROS family zinc finger 1' 603023 'Janus kinase 2' 'WW domain containing oxidoreductase' 605131 'ataxin 3' 'BCL2 like 1' 600039 'RB transcriptional corepressor 1' 'BCL2 like 11' 603827 'transferrin receptor' 'cyclin D1' 168461 'C-C motif chemokine ligand 2' 'TNF superfamily member 10' 603598 'prostaglandin-endoperoxide synthase 2'", header = T) 并重写NSApplication。这样可以看到通过覆盖nextEventMatchingMask:untilDate:inMode:dequeue:而无法看到的鼠标事件,例如,在跟踪滚动条时。我不确定这个问题与键盘事件是否有关,但是其他偶然发现此问题的人可能会感兴趣。