Демон отслеживания мыши

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

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

14
задан Reinstate Monica 7 October 2013 в 20:28
поделиться

2 ответа

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

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

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

[NSEvent removeMonitor:eventHandler];
19
ответ дан 1 December 2019 в 07:50
поделиться

Напишите 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.

15
ответ дан 1 December 2019 в 07:50
поделиться