Демон отслеживания мыши - PullRequest
14 голосов
/ 28 июня 2010

Мне нужно что-то написать, используя Какао для отображения необработанных данных о движении мыши.Оптимально, приложение будет просто маленьким демоном, который будет работать, передавая данные серверу сокетов, к которому может подключиться другое приложение, чтобы получить доступ к событиям.

Может ли кто-нибудь указать мне правильное направление в отношенииподходить и инструменты?Я даже не уверен, с чего начать прямо сейчас.

Ответы [ 2 ]

19 голосов
/ 28 июня 2010

Другой простой способ сделать это - добавить глобальный монитор событий (только 10.6, однако):

id eventHandler = [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent * mouseEvent) {
  NSLog(@"Mouse moved: %@", NSStringFromPoint([mouseEvent locationInWindow]));
}];

Затем, когда вы закончите отслеживание, вы делаете:

[NSEvent removeMonitor:eventHandler];
15 голосов
/ 28 июня 2010

Написать 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.

...