Utilizzando i touchBeganWithEvent, toccaEndedWithEvent, ecc. È possibile ottenere i dati tattili dal trackpad multitouch, ma esiste un modo per bloccare i dati di tocco dallo spostamento del mouse/attivare i gesti dell'intero sistema (simile a cosa si fa nell'input di testo cinese)?Acquisizione di tutti gli input del trackpad multitouch in Cocoa
risposta
Come notato da valexa, utilizzando NSEventMask per CGEventTap è un hack. Tarmes rileva inoltre che la risposta di Rob Keniger non funziona più (OS X> = 10.8). Fortunatamente, Apple ha fornito un modo per farlo abbastanza facilmente usando kCGEventMaskForAllEvents
e convertendo il CGEventRef a un NSEvent all'interno del callback:
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();
}
Nota che la chiamata a CFRunLoopRun()
è incluso in quanto questo frammento è stato preso da un progetto che non è stato possibile utilizzare NSApplication ma invece ha avuto un CFRunLoop bare-bone. Omettalo se usi NSApplication.
AGGIORNAMENTO: la mia risposta di seguito non funziona più. Vedere la risposta here.
In genere per eseguire questa operazione è necessario utilizzare un evento Evento Quartz, anche se gli eventi di tocco non sembrano essere "ufficialmente" supportati dall'API CGEvent. I tipi di eventi non multitouch in NSEvent.h sembrano essere associati ai tipi CGEvent in CGEventTypes.h, quindi quelli multitouch probabilmente funzioneranno anche se non sono documentati.
Per impedire la propagazione degli eventi, è necessario restituire NULL dall'evento tap callback.
avreste bisogno di un po 'di codice come questo:
#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;
}
non è corretto che NSEventMasks esegua la mappatura su CGEventMasks quello che effettivamente accade è che l'impostazione della maschera è uguale all'impostazione della maschera su kCGEventMaskForAllEvents e il risultato è ottenere un vapore di NSEventTypeGesture solo eventi per ogni singolo tocco sul trackpad, la soppressione di che restituendo NULL blocca effettivamente ogni tipo di gesto. – valexa
Ho provato a farlo funzionare con 10.8 e non sembra funzionare - i gesti non sono più passati attraverso EventTap. Non credo che tu abbia trovato un'altra soluzione? – tarmes
-1: non funziona con il 10.8. Suggerisco invece di utilizzare questa risposta: http://stackoverflow.com/a/13755292/901641 – ArtOfWarfare
Suggerisco di aggiornare la risposta accettata. – ArtOfWarfare