鼠标跟踪守护进程

发布于 2024-09-06 23:56:22 字数 138 浏览 2 评论 0原文

我需要使用 Cocoa 编写一些内容来显示原始鼠标移动数据。理想情况下,该应用程序只是一个运行的小守护程序,将数据传递到套接字服务器,另一个应用程序可以利用该服务器来访问事件。

谁能在方法和工具方面为我指明正确的方向?我现在什至不知道从哪里开始。

I need to write something using Cocoa to surface raw mouse movement data. Optimally, the app would just be a little daemon that would run, passing the data to a socket server which another application could tap into to gain access to the events.

Can anyone point me in the right direction with regard to approach and tools? I am not even sure where to begin with this right now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绝情姑娘 2024-09-13 23:56:22

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

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

然后当您完成跟踪时,您可以:

[NSEvent removeMonitor:eventHandler];

The other simple way to do this is to add a global event monitor (10.6 only, however):

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

Then when you're done tracking, you do:

[NSEvent removeMonitor:eventHandler];
大姐,你呐 2024-09-13 23:56:22

编写一个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 方法,可以做几乎相同的事情;基本上,Cocoa 在幕后所做的与我在上面的示例中所做的相同,只是包装到静态方法中。 Dave 的代码仅适用于 10.6,但上述代码适用于 10.4、10.5 和 10.6。

Write an EventTap. Documentation can be found here.

In MacOS X every event (e.g. every keyboard key pressed, every mouse key pressed or mouse movement) creates an event that travels the following path:

Driver (Kernel) -> Window Server (privileged) -> User (Login) Session -> Active Application

Everywhere where I wrote an arrow (->) an EventTap can be placed to either only look at the event (a listen only EventTap) or to either modify or drop the event (an event filtering EventTap). Please note that to catch an event between Driver and WindowServer, your daemon must run with root privileges.

Here is some sample code:

// 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;
}

The answer from Dave is the nicer Cocoa way of doing pretty much the same thing; basically Cocoa does the same as I do in my sample above behind the scenes, just wrapped into a static method. The code of Dave works only on 10.6, though, the above works in 10.4, 10.5 and 10.6.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文