Alex Rivera | Logout

Mouse tracking daemon

Asked 2010-06-28T18:02:42.033
16

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.

Edit
Report

2 Answers

19

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];
answered 2010-06-28T19:40:24.773
16

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 (
        kCGSessionEv
answered 2010-06-28T19:29:18.003

Your Answer