我正在尝试添加一个事件陷阱来启用/禁用魔术触控板上的事件。我认为这将是直截了当的,即注册一个事件陷阱,并在需要时通过返回NULL
来丢弃该事件。我们的想法是使用pad来进行一些特定的,耗时的数据输入,输入数据的应用程序是第三方的,所以我不能只是添加代码来实现我想要的。所以我想我会监视系统事件,然后通过一堆CGEventCreateKeyboardEvent
s发送所需的输入。
问题是返回null似乎没有丢弃事件,更多的调查表明这不仅限于来自触控板的那些,而且还是我的默认USB鼠标。
我的代码如下。以下是我希望不能移动鼠标,如果我改变(A)使用kCGEventScrollWheel
或kCGEventLeftMouseDragged
然后消耗事件,即滚动或左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应该有效)。答案 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