Написать EventTap.Документация может быть найдена здесь .
В MacOS X каждое событие (например, каждая нажатая клавиша клавиатуры, каждая нажатая клавиша мыши или движение мыши) создает событие, которое перемещается по следующему пути:
Driver (Kernel) -> Window Server (privileged) -> User (Login) Session -> Active Application
Везде, где я написал стрелку (->
), EventTap может быть размещен либо для просмотра только события (EventTap только для прослушивания), либо для изменения или удаления события (фильтрация событий EventTap).Обратите внимание, что для перехвата события между Driver и WindowServer ваш демон должен работать с привилегиями root.
Вот пример кода:
// Compile with:
// gcc -framework ApplicationServices -o MouseWatcher MouseWatcher.c
//
// Start with:
// ./MouseWatcher
//
// Terminate by hitting CTRL+C
#include <ApplicationServices/ApplicationServices.h>
static CGEventRef myEventTapCallback (
CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void * refcon
) {
CGPoint mouseLocation;
// If we would get different kind of events, we can distinguish them
// by the variable "type", but we know we only get mouse moved events
mouseLocation = CGEventGetLocation(event);
printf(
"Mouse is at x/y: %ld/%ld\n",
(long)mouseLocation.x,
(long)mouseLocation.y
);
// Pass on the event, we must not modify it anyway, we are a listener
return event;
}
int main (
int argc,
char ** argv
) {
CGEventMask emask;
CFMachPortRef myEventTap;
CFRunLoopSourceRef eventTapRLSrc;
// We only want one kind of event at the moment: The mouse has moved
emask = CGEventMaskBit(kCGEventMouseMoved);
// Create the Tap
myEventTap = CGEventTapCreate (
kCGSessionEventTap, // Catch all events for current user session
kCGTailAppendEventTap, // Append to end of EventTap list
kCGEventTapOptionListenOnly, // We only listen, we don't modify
emask,
&myEventTapCallback,
NULL // We need no extra data in the callback
);
// Create a RunLoop Source for it
eventTapRLSrc = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault,
myEventTap,
0
);
// Add the source to the current RunLoop
CFRunLoopAddSource(
CFRunLoopGetCurrent(),
eventTapRLSrc,
kCFRunLoopDefaultMode
);
// Keep the RunLoop running forever
CFRunLoopRun();
// Not reached (RunLoop above never stops running)
return 0;
}
Ответ от Dave - лучший способ Cocoaделать почти то же самое;в основном, Какао делает то же самое, что и я в моем примере выше за кулисами, просто в статическом методе.Код Дейва работает только на 10.6, а выше работает в 10.4, 10.5 и 10.6.