How can I listen for a mouse event in Python on Mac?
I need to listen for global mouse events(not bound to an app) on my Mac in an app written in Python.
I'm using PyObjC, but I can't figure out how to do it. Plain ObjC examples or other Python techniques also appreciated.
My c开发者_开发百科ode so far:
from Quartz import *
def MyFunction(proxy, type, event):
print event
CGEventTapCreate(kCGHIDEventTap, kCGTailAppendEventTap, kCGEventTapOptionListenOnly, kCGEventLeftMouseDown, MyFunction)
== Segmentation fault
I know I need to add it to an event source later on, but I need to get this working first.
[update]
Using PyObjC form Macports solved the segfault, so now I wrote this:
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();
But this just runs forever and does not respond to mouse events, what is wrong?
The fourth parameter of CGEventTapCreate is CGEventMask eventsOfInterest
, and you gave it kCGEventLeftMouseDown
which is an enum of type _CGEventType
. Instead of the integer constant, you need to flip the appropriate bit in the bitmask. You can do this using CGEventMaskBit
So instead of this:
tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly, kCGEventLeftMouseDown, MyFunction, None)
We can do this:
tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly, CGEventMaskBit(kCGEventLeftMouseDown),
MyFunction, None)
or equivalently:
tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly, (1 << kCGEventLeftMouseDown),
MyFunction, None)
The documentation for CGEventTapCreate (http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate) says that you need to be root to use kCGHIDEventTap. Are you running your script as root? (sudo is one way to do this)
If you are, you should also check whether tap is None; that will help narrow down the problem. There are several error conditions listed in the documentation that can cause CGEventTapCreate to return NULL, which should be reflected as None in Python.
First, CGEventTapCreate and CGEventTapCreateForPSN leak some memory when they are called. This is needed to avoid memory management problems. It is therefore advisable not to call these functions, are at least call them a small number of times.
Now, a mouse event works something like this:
evt = CGEventCreateMouseEvent(None, kCGEventLeftMouseDown, (80, 90), kCGMouseButtonLeft)
self.failUnlessIsInstance(evt, CGEventRef)
精彩评论