Захват всех входных данных мультитач-трекпада в Cocoa

StackOverflow https://stackoverflow.com/questions/1383528

Вопрос

Используя touchesBeganWithEvent, touchesEndedWithEvent и т. д., вы можете получить данные касания с мультисенсорного трекпада, но есть ли способ заблокировать эти данные касания от перемещения мыши/активации общесистемных жестов (аналогично тому, что делается при вводе текста на китайском языке) ?

Это было полезно?

Решение

Как отмечает valexa, использование NSEventMask для CGEventTap — это хак.Тармес также отмечает, что ответ Роба Кенигера больше не работает (OS X >= 10.8).К счастью, Apple предоставила способ сделать это довольно легко, используя 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.

Другие советы

ОБНОВЛЯТЬ:мой ответ ниже больше не работает.Посмотреть ответ здесь.

Обычно для этого вам нужно использовать Quartz Event Tap, хотя события касания, похоже, «официально» не поддерживаются CGEvent API.Типы событий без мультитача в NSEvent.h, похоже, сопоставляются с типами CGEvent в CGEventTypes.h, поэтому мультитач, вероятно, будет работать, даже если они не документированы.

Чтобы заблокировать распространение событий, вам необходимо вернуть 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top