鼠标跟踪守护进程

鼠标跟踪守护进程

问题描述:

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

任何人都可以在方向和工具方面指出正确的方向吗?我甚至不知道现在该从哪里开始。

其他简单的方式做,这是add a global event monitor(10.6只,不过):

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

然后,当你做跟踪,你这样做:

[NSEvent removeMonitor:eventHandler]; 
+0

但只适用于10.6,而我的代码甚至可以使用10.4以上:-P – Mecki 2010-06-28 19:48:25

+1

@Mecki yep,这是唯一的警告。如果海报可以专门定位10.6,那么全球显示器肯定更容易。否则,他需要一个事件点击。 – 2010-06-28 19:49:17

+0

感谢您的信息。我试着将Dave的代码添加到我的应用程序中,但是我得到一个编译错误,说NSEvent可能不会响应mouseLocation,并且NSStringFromPoint传递了一个无效参数。 (NSEvent * mouseEvent)之前的插入符号是什么?这是问题吗?我不熟悉这种语法... 鉴于我不能尝试这个,让我问,这会给我的鼠标数据?基本上,即使鼠标固定在左上角,我也需要知道用户继续向上移动并离开,就是这样。这会实现吗? 再次感谢! – Raconteur 2010-06-28 21:09:44

写一个EventTap。文档可以是found here

在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和我在后面的示例中做的一样,只是包装成静态方法。 Dave的代码只能在10.6上运行,不过,上面的代码在10.4,10.5和10.6中运行。

+0

嗨Mecki,感谢这个。我使用的是10.6,因此,Dave描述的单线方法是更理想的解决方案。感谢您的意见! – Raconteur 2010-06-28 22:26:44

+0

将'self'作为'refcon'参数传入,以便在触发时可以调用ObjC类中的方法。请参阅http://stackoverflow.com/a/14985036/130910 – vaughan 2014-03-03 06:17:01

+1

调用'[NSEvent eventWithCGEvent:event]'得到一个更好的API用于处理ObjC代码的'NSEvent'。在ARC你需要桥接。例如:'[(__bridge MyClass *)refcon myHandlerInstanceMethod:e];' – vaughan 2014-03-03 06:19:32