使用事件点击消耗OSX鼠标/触控板事件

时间:2010-12-23 12:02:02

标签: objective-c cocoa macos

我正在尝试添加一个事件陷阱来启用/禁用魔术触控板上的事件。我认为这将是直截了当的,即注册一个事件陷阱,并在需要时通过返回NULL来丢弃该事件。我们的想法是使用pad来进行一些特定的,耗时的数据输入,输入数据的应用程序是第三方的,所以我不能只是添加代码来实现我想要的。所以我想我会监视系统事件,然后通过一堆CGEventCreateKeyboardEvent s发送所需的输入。

问题是返回null似乎没有丢弃事件,更多的调查表明这不仅限于来自触控板的那些,而且还是我的默认USB鼠标。

我的代码如下。以下是我希望不能移动鼠标,如果我改变(A)使用kCGEventScrollWheelkCGEventLeftMouseDragged然后消耗事件,即滚动或左btn拖动不发生。这是否意味着并非所有事件都可以丢弃?希望我只是遗漏了一些明显的东西

  #define case_print(a) case a: printf("%s - %d\n",#a,a); break;


  CGEventRef eventOccurred(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
    int subType =  CGEventGetIntegerValueField(event, kCGMouseEventSubtype);
    if (type == NSEventTypeGesture || subType == NX_SUBTYPE_MOUSE_TOUCH) {
        printf("touchpad\n");

        switch(type) {
                case_print(kCGEventNull)
                case_print(kCGEventLeftMouseDown)
                case_print(kCGEventLeftMouseUp)
                case_print(kCGEventRightMouseDown)
                case_print(kCGEventRightMouseUp)
                case_print(kCGEventMouseMoved)
                case_print(kCGEventLeftMouseDragged)
                case_print(kCGEventRightMouseDragged)
                case_print(kCGEventScrollWheel)
                case_print(kCGEventOtherMouseDown)
                case_print(kCGEventOtherMouseUp)
                case_print(kCGEventOtherMouseDragged)
                case_print(kCGEventTapDisabledByTimeout)
                case_print(kCGEventTapDisabledByUserInput)
                case_print(NSEventTypeGesture)
                case_print(NSEventTypeMagnify)
                case_print(NSEventTypeSwipe)
                case_print(NSEventTypeRotate)
                case_print(NSEventTypeBeginGesture)
                case_print(NSEventTypeEndGesture)
            default:
                printf("default: %d\n",type);
                break;    
        }

        event = NULL;
    }  else {
        if (type == kCGEventMouseMoved) {  // (A)
            printf("discarding mouse event");
            event = NULL;
        }
    }

    return event;
}


CFMachPortRef createEventTap() {  
    CGEventMask eventMask = NSAnyEventMask;

    if (!AXAPIEnabled() && !AXIsProcessTrusted()) { 
        printf("axapi not enabled");
    } 

    return CGEventTapCreate(kCGHIDEventTap, 
                            kCGHeadInsertEventTap, 
                            kCGEventTapOptionDefault, 
                            eventMask, 
                            eventOccurred, 
                            NULL); 
}

int main (int argc, const char * argv[]) {
    CFMachPortRef tap = createEventTap();

    if (tap) {
        CFRunLoopSourceRef rl = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0);
        CFRunLoopAddSource(CFRunLoopGetMain(), rl, kCFRunLoopCommonModes);
        CGEventTapEnable(tap, true);
        CFRunLoopRun();

        printf("Tap created.\n");
        sleep(-1);
    } else {
        printf("failed!\n");
    }

    return 0;
}

注意,虽然我认为辅助功能选项不会影响除键盘事件以外的任何内容,但不输出“未启用axapi”。

顺便说一句,我已经看过一些关于如何从触摸板上获取事件的类似帖子,没有什么适用于丢弃它们(除了返回null应该有效)。

4 个答案:

答案 0 :(得分:4)

我认为我们不可能简单地丢弃这些事件。从CGEventTypes.h头文件:

  

“传递给回调的事件是   由调用代码保留,并且是   在回调返回后释放   并将数据传回给   事件系统。如果是另一个事件   由回调函数返回,   然后该事件将被释放   调用代码和   原始事件,事件数据后   已被传回活动   系统“。

我已经玩过这个了一下,似乎在回调之后窗口服务器再次主动检查你对事件做了什么。它只允许删除键事件和鼠标上/下事件,但就像忽略鼠标移动事件的删除一样(好吧,鼠标渲染在别处处理,我猜)它似乎忽略了删除(即你的回调返回NULL)用于鼠标手势。

图中没有具体说明手势的点击(没有在此级别定义的类型)。

我尝试返回一个不同的事件(一键按下),然后再对原始手势处理此事件。在回调中释放事件也不会(当然)只会导致异常。

我唯一没有尝试的是直接操作传递的CGEvent的内部数据,至少使手势无效(删除所有移动等),但这有点难,因为没有定义的特定方法来做到这一点。我很确定所需的信息是在可通过CGEventSet *方法访问的各个字段中的某个位置。

我向下看IOLLEvent.h来找出他们的数据结构,但这对于我的品味来说太难看了。让我们希望Lion提供关于CF级别事件的手势类型的更多信息。

答案 1 :(得分:3)

我可以在10.6上证实,以下两种方法都没有成功实现这一目的。

1 - 返回NULL

2 - 返回具有前一光标位置的新鼠标事件

3 - 返回传递的事件,其中kCGMouseEventDelta更改为0

我不能说10.7但是我只是说我不会抱有希望。

然而,有一件事你可以做而不是放弃移动使用CGWarpMouseCursorPosition将其移回到前一个位置,实际上光标将停止移动而第一个上只有轻微的变化。

答案 2 :(得分:1)

如果您的点击是被动的,则返回NULL将使事件流不受影响。来自CGEventTapCallBack参考文档:

  

“如果事件点击是被动的   监听器,你的回调函数可能   返回传入的事件,或   空值。在任何一种情况下,事件流   没有受到影响。“

但是,您的点按似乎是活跃的。因此,返回的NULL应该删除该事件。您是否考虑过修改事件以使行动无效?

另请注意,调用CGEventTapCreate需要root用户权限才能拦截所有事件。您的流程是否以root身份运行?

答案 3 :(得分:1)

CGAssociateMouseAndMouseCursorPosition(FALSE);

当您的应用处于有效状态时,会阻止鼠标正常运行。

还在探索我是否可以将其扩展到全球应用......

http://lists.apple.com/archives/quartz-dev/2007/May/msg00112.html