2009-09-05 13 views

Respuesta

6

Como señaló valexa, utilizando NSEventMask para CGEventTap es un truco. Tarmes también nota que la respuesta de Rob Keniger ya no funciona (OS X> = 10.8). Por suerte, Apple ha proporcionado una manera de hacer esto con bastante facilidad mediante el uso de kCGEventMaskForAllEvents y convirtiendo el CGEventRef a un NSEvent dentro de la devolución de llamada:

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(); 
} 

Tenga en cuenta que la llamada a CFRunLoopRun() se incluye ya que este fragmento fue tomado de un proyecto que no podía usar NSApplication, sino que tenía un CFRunLoop básico. Omita si usa NSApplication.

2

ACTUALIZACIÓN: mi respuesta a continuación ya no funciona. Ver la respuesta here.

Por lo general, para hacer esto necesitarás usar un toque de Evento de Cuarzo, aunque los eventos táctiles no parecen ser "oficialmente" compatibles con la API de CGEvent. Los tipos de eventos no multitáctiles en NSEvent.h parecen correlacionarse con los tipos CGEvent en CGEventTypes.h, por lo que los multitouch probablemente funcionen, incluso si no están documentados.

Para bloquear la propagación de eventos, debe devolver NULL desde la devolución de llamada de evento.

que había necesidad alguna código como este:

#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; 
} 
+0

es incorrecto que NSEventMasks asigne a CGEventMasks lo que realmente sucede es que establecer la máscara en esos casos es lo mismo que establecer la máscara en kCGEventMaskForAllEvents y su resultado es obtener un vapor de NSEventTypeGesture solo eventos por cada toque en el panel táctil, la supresión de que al devolver NULL bloquea cualquier tipo de gesto. – valexa

+0

He intentado esto ejecutando bajo 10.8 y parece que no funciona - los gestos ya no se pasan a través de EventTap. Supongo que no encontraste otra solución. – tarmes

+0

-1: No funciona por debajo de 10.8. Sugiero usar esta respuesta en su lugar: http://stackoverflow.com/a/13755292/901641 – ArtOfWarfare

Cuestiones relacionadas