Я должен записать что-то с помощью Какао для обработки поверхности необработанных данных движения мыши. Оптимально, приложение просто было бы маленьким демоном, который будет работать, передавая данные серверу сокета, которым другое приложение могло насладиться для получения доступа к событиям.
Кто-либо может указать на меня в правильном направлении относительно подхода и инструментов? Я даже не уверен, где начать с этого прямо сейчас.
Другой простой способ сделать это - добавить глобальный монитор событий (однако только для версии 10.6):
id eventHandler = [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent * mouseEvent) {
NSLog(@"Mouse moved: %@", NSStringFromPoint([mouseEvent locationInWindow]));
}];
Затем, когда вы закончите отслеживая, вы выполняете:
[NSEvent removeMonitor:eventHandler];
Напишите EventTap. Документацию можно найти здесь .
В MacOS X каждое событие (например, каждая нажатая клавиша клавиатуры, каждая нажатая клавиша мыши или движение мыши) создает событие, которое проходит по следующему пути:
Driver (Kernel) -> Window Server (privileged) -> User (Login) Session -> Active Application
Везде, где я написал стрелку ( ->
) EventTap можно разместить либо только для просмотра события (EventTap только для прослушивания), либо для изменения или удаления события (EventTap с фильтрацией событий). Обратите внимание, что для перехвата события между драйвером и 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;
}
Ответ Дэйва - более приятный способ какао сделать то же самое; в основном Cocoa делает то же самое, что и я в моем примере выше, за кулисами, просто завернутый в статический метод. Код Дейва работает только на 10.6, хотя вышеперечисленное работает на 10.4, 10.5 и 10.6.