2010-02-25 8 views
9

Ho bisogno di ascoltare eventi mouse globali (non legati a un'app) sul mio Mac in un'app scritta in Python.Come posso ascoltare un evento del mouse in Python su Mac?

Sto usando PyObjC, ma non riesco a capire come farlo. Sono stati apprezzati anche semplici esempi ObjC o altre tecniche Python.

Il mio codice finora:

from Quartz import * 
def MyFunction(proxy, type, event): 
    print event 

CGEventTapCreate(kCGHIDEventTap, kCGTailAppendEventTap, kCGEventTapOptionListenOnly, kCGEventLeftMouseDown, MyFunction) 

== Segmentation fault

so che ho bisogno di aggiungerlo a una fonte di evento più tardi, ma ho bisogno di ottenere questo lavoro prima.

[update]

Utilizzando PyObjC forma MacPorts risolto il segfault, così ora ho scritto questo:

from Quartz import * 

def MyFunction(p, t, e, c): 
    print e 

tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, kCGEventLeftMouseDown, MyFunction, None) 

runLoopSource = CFMachPortCreateRunLoopSource(None, tap, 0); 
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); 
CGEventTapEnable(tap, True); 

CFRunLoopRun(); 

Ma questo solo corre sempre e non risponde agli eventi del mouse, ciò che è sbagliato?

risposta

2

Il quarto parametro di CGEventTapCreate è CGEventMask eventsOfInterest e lo ha fornito kCGEventLeftMouseDown che è un enum di tipo _CGEventType. Invece della costante intera, è necessario capovolgere il bit appropriato nella maschera di bit. È possibile farlo utilizzando CGEventMaskBit

Così, invece di questo:

tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
    kCGEventTapOptionListenOnly, kCGEventLeftMouseDown, MyFunction, None) 

possiamo fare questo:

tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
    kCGEventTapOptionListenOnly, CGEventMaskBit(kCGEventLeftMouseDown), 
    MyFunction, None) 

o equivalentemente:

tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
    kCGEventTapOptionListenOnly, (1 << kCGEventLeftMouseDown), 
    MyFunction, None) 
+0

questa dovrebbe essere la risposta corretta –

-1

In primo luogo, CGEventTapCreate e CGEventTapCreateForPSN perdita po 'di memoria quando sono chiamati. Questo è necessario per evitare problemi di gestione della memoria. È quindi opportuno che non chiami queste funzioni, almeno lo chiamino un numero limitato di volte.

Ora, un evento del mouse funziona in questo modo:

evt = CGEventCreateMouseEvent(None, kCGEventLeftMouseDown, (80, 90), kCGMouseButtonLeft) 
self.failUnlessIsInstance(evt, CGEventRef) 
+1

Non voglio inviare eventi, voglio ascoltarli per loro. CGEventCreateMouseEvent è per la creazione di eventi, non i tocchi di eventi. – Pepijn

+0

Siamo spiacenti. Mi sono incasinato con l'esempio di codice sbagliato. –

+1

C'è un altro metodo per l'evento Tap che pensavo di darti. –

1

La documentazione per CGEventTapCreate (http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate) dice che è necessario essere root per usare kCGHIDEventTap. Stai eseguendo il tuo script come root? (sudo è un modo per farlo)

Se lo sei, dovresti anche controllare se Tap è None; questo aiuterà a restringere il problema. Nella documentazione sono elencate diverse condizioni di errore che possono causare CGEventTapCreate per restituire NULL, che dovrebbe essere visualizzato come None in Python.

+0

Sudo o non fa la differenza, sia tap che runLoopSource contengono qualcosa. C'è un'alternativa a kCGHIDEventTap? Ho notato che CFRunLoopRunInMode (kCFRunLoopDefaultMode, 20, False) viene eseguito per 20 secondi, ma la fornitura di True termina immediatamente, ma non viene ancora emessa da MyFunction. – Pepijn

+0

Potrebbe essere qualcosa a che fare con la definizione del CGEventRef che stai tentando di stampare? Forse potresti provare a stampare una stringa costante in MyFunction solo per essere sicuro. A parte questo, non lo so davvero. –

+0

Ho provato a stampare solo "ciao", ma non è stato d'aiuto. Potrebbe essere che la funzione è chiamata da qualche parte dove stdout è impostato in modo diverso? – Pepijn