鼠标跟踪守护程序

Rac*_*eur 14 mouse cocoa objective-c mouseevent

我需要使用Cocoa编写一些东西来表示原始鼠标移动数据.最理想的情况是,应用程序只是一个可以运行的小守护进程,将数据传递给另一个应用程序可以访问的套接字服务器以获取对事件的访问权限.

任何人都能指出我在方法和工具方面的正确方向吗?我现在还不确定从哪里开始.

Dav*_*ong 19

另一种简单的方法是添加一个全局事件监视器(仅限10.6):

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

然后,当您完成跟踪时,您会执行以下操作:

[NSEvent removeMonitor:eventHandler];
Run Code Online (Sandbox Code Playgroud)


Mec*_*cki 15

写一个EventTap.文档可以在这里找到.

在MacOS X中,每个事件(例如,按下每个键盘键,按下每个鼠标键或鼠标移动)都会创建一个沿着以下路径传播的事件:

Driver (Kernel) -> Window Server (privileged) -> User (Login) Session -> Active Application
Run Code Online (Sandbox Code Playgroud)

在我写了一个箭头(->)的地方,可以放置一个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;
}
Run Code Online (Sandbox Code Playgroud)

Dave的答案是更好的Cocoa方式做同样的事情; 基本上Cocoa和我在幕后的示例中做的一样,只是包装成静态方法.Dave的代码仅适用于10.6,但上述工作在10.4,10.5和10.6中.