Как я могу прослушать событие мыши в Python на Mac?

Мне нужно прослушивать глобальные события мыши (не привязанные к приложению) на моем Mac в приложении, написанном на Python.

Я использую PyObjC, но не могу понять, как это сделать. Простые примеры ObjC или другие методы Python также приветствуются.

Мой код до сих пор:

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

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

== Ошибка сегментации

Я знаю, что позже мне нужно добавить его в источник событий, но сначала мне нужно, чтобы это заработало.

[Обновить]

Используя форму PyObjC, Macports решил проблему сегментации, поэтому теперь я написал следующее:

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

Но это просто работает вечно и не реагирует на события мыши, что не так?


person Pepijn    schedule 25.02.2010    source источник


Ответы (3)


Четвертый параметр CGEventTapCreate — CGEventMask eventsOfInterest, и вы указали ему kCGEventLeftMouseDown, который является перечислением типа _CGEventType. Вместо целочисленной константы вам нужно перевернуть соответствующий бит в битовой маске. Вы можете сделать это с помощью CGEventMaskBit

Итак, вместо этого:

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

Мы можем сделать это:

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

или эквивалентно:

tap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
    kCGEventTapOptionListenOnly, (1 << kCGEventLeftMouseDown),
    MyFunction, None)
person Felix Fung    schedule 19.12.2010

Документация по CGEventTapCreate (http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate) говорит, что вам нужно быть root, чтобы использовать kCGHIDEventTap. Вы запускаете свой скрипт как root? (sudo - один из способов сделать это)

Если это так, вам также следует проверить, не имеет ли значение tap значение None; это поможет сузить проблему. В документации перечислены несколько условий ошибки, которые могут привести к тому, что CGEventTapCreate вернет NULL, что должно быть отражено как None в Python.

person Scott Wolchok    schedule 07.03.2010
comment
Sudo или нет, не имеет значения, и tap, и runLoopSource что-то содержат. Есть ли альтернатива kCGHIDEventTap? Я заметил, что CFRunLoopRunInMode(kCFRunLoopDefaultMode, 20, False) работает в течение 20 секунд, но предоставление True немедленно заканчивается, но все еще не выводится из MyFunction. - person Pepijn; 07.03.2010
comment
Может ли это быть как-то связано со строкой CGEventRef, которую вы пытаетесь напечатать? Возможно, вы могли бы попробовать напечатать постоянную строку в MyFunction, чтобы убедиться. Кроме этого, я действительно не знаю. - person Scott Wolchok; 08.03.2010
comment
Я пытался просто напечатать «привет», но это тоже не помогло. Может ли быть, что функция вызывается где-то, где стандартный вывод установлен по-другому? - person Pepijn; 08.03.2010

Во-первых, при вызове CGEventTapCreate и CGEventTapCreateForPSN происходит утечка памяти. Это нужно, чтобы избежать проблем с управлением памятью. Поэтому рекомендуется не вызывать эти функции, по крайней мере вызывать их небольшое количество раз.

Теперь событие мыши работает примерно так:

evt = CGEventCreateMouseEvent(None, kCGEventLeftMouseDown, (80, 90), kCGMouseButtonLeft)
self.failUnlessIsInstance(evt, CGEventRef)
person Todd Moses    schedule 25.02.2010
comment
Я не хочу отправлять события, я хочу их слушать. CGEventCreateMouseEvent предназначен для создания событий, а не касаний событий. - person Pepijn; 26.02.2010
comment
Есть еще один метод для Tap Event, который, как я думал, я вам дам. - person Todd Moses; 26.02.2010