捕获Cocoa中的所有多点触控触摸板输入

13

使用touchesBeganWithEvent、touchesEndedWithEvent等方法,您可以从多点触控触摸板获取触摸数据,但是否有一种方法可以阻止该触摸数据移动鼠标/激活系统范围手势(类似于中文文本输入中所做的操作)?

使用touchesBeganWithEvent、touchesEndedWithEvent等方法,您可以从多点触控触摸板获取触摸数据,但是否有一种方法可以阻止该触摸数据移动鼠标/激活系统范围手势(类似于中文文本输入中所做的操作)?

1
我建议更新被接受的答案。 - ArtOfWarfare
2个回答

7
如valexa所指出的,使用NSEventMask作为CGEventTap是一种hack方法。Tarmes还指出Rob Keniger的答案不再适用(OS X >= 10.8)。幸运的是,苹果提供了一种很容易的方法来实现这一点,即使用kCGEventMaskForAllEvents并在回调函数中将CGEventRef转换为NSEvent:
NSEventMask eventMask = NSEventMaskGesture|NSEventMaskMagnify|NSEventMaskSwipe|NSEventMaskRotate|NSEventMaskBeginGesture|NSEventMaskEndGesture;

CGEventRef eventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, void *refcon) {
  // convert the CGEventRef to an NSEvent
  NSEvent *event = [NSEvent eventWithCGEvent:eventRef];

  // filter out events which do not match the mask
  if (!(eventMask & NSEventMaskFromType([event type]))) { return [event CGEvent]; }

  // do stuff
  NSLog(@"eventTapCallback: [event type] = %d", [event type]);

  // return the CGEventRef
  return [event CGEvent];
}

void initCGEventTap() {
  CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, kCGEventMaskForAllEvents, eventTapCallback, nil);
  CFRunLoopAddSource(CFRunLoopGetCurrent(), CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0), kCFRunLoopCommonModes);
  CGEventTapEnable(eventTap, true);
  CFRunLoopRun();
}

请注意,调用 CFRunLoopRun() 是因为这段代码片段来自一个不能使用 NSApplication 但是必须使用基本的 CFRunLoop 的项目中。如果你使用 NSApplication,则可以省略该调用。

2

更新:下面的答案不再适用。请参见此处的答案。

通常,您需要使用Quartz事件点击才能实现此操作,尽管触摸事件似乎并没有被CGEvent API“官方”支持。NSEvent.h中的非多点触控事件类型似乎映射到CGEventTypes.h中的CGEvent类型,因此即使它们没有记录,多点触控事件也可能有效。

为了阻止事件传播,您需要从事件点击回调中返回NULL。

您需要像这样的代码:

#import <ApplicationServices/ApplicationServices.h>

//assume CGEventTap eventTap is an ivar or other global

void createEventTap(void)
{
 CFRunLoopSourceRef runLoopSource;

 //listen for touch events
 //this is officially unsupported/undocumented
 //but the NSEvent masks seem to map to the CGEvent types
 //for all other events, so it should work.
 CGEventMask eventMask = (
  NSEventMaskGesture       |
  NSEventMaskMagnify       |
  NSEventMaskSwipe         |
  NSEventMaskRotate        |
  NSEventMaskBeginGesture  |
  NSEventMaskEndGesture
 );

 // Keyboard event taps need Universal Access enabled, 
 // I'm not sure about multi-touch. If necessary, this code needs to 
 // be here to check whether we're allowed to attach an event tap
 if (!AXAPIEnabled()&&!AXIsProcessTrusted()) { 
  // error dialog here 
  NSAlert *alert = [[[NSAlert alloc] init] autorelease];
  [alert addButtonWithTitle:@"OK"];
  [alert setMessageText:@"Could not start event monitoring."];
  [alert setInformativeText:@"Please enable \"access for assistive devices\" in the Universal Access pane of System Preferences."];
  [alert runModal];
  return;
 } 


 //create the event tap
 eventTap = CGEventTapCreate(kCGHIDEventTap, //this intercepts events at the lowest level, where they enter the window server
        kCGHeadInsertEventTap, 
        kCGEventTapOptionDefault, 
        eventMask,
        myCGEventCallback, //this is the callback that we receive when the event fires
        nil); 

 // Create a run loop source.
 runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

 // Add to the current run loop.
 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

 // Enable the event tap.
 CGEventTapEnable(eventTap, true);
}


//the CGEvent callback that does the heavy lifting
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon)
{
 //handle the event here
 //if you want to capture the event and prevent it propagating as normal, return NULL.

 //if you want to let the event process as normal, return theEvent.
 return theEvent;
}

1
“NSEventMasks映射到CGEventMasks”是错误的,实际上设置掩码与设置掩码为“kCGEventMaskForAllEvents”相同,其结果是在触摸板上的每个单独触摸都会获得仅限于“NSEventTypeGesture”的事件流,通过返回NULL抑制这些事件可以阻挡任何类型的手势。 - valexa
我已经尝试在10.8下运行,但似乎不起作用了 - 手势不再通过EventTap传递。我不确定你是否找到了其他的解决方案? - tarmes
-1:它在10.8下无法工作。我建议使用这个答案代替:https://dev59.com/onM_5IYBdhLWcg3waiiJ#13755292 - ArtOfWarfare
这个回答是在2009年发布的,它已经过时了,这并不奇怪。只是说一下。 - Rob Keniger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接