Prevent `mouseMovedEvent` callback from processing the movement? Or globally hide cursor momentarily?
Asked Answered
B

1

3

I have a global app that prevents the mouse from moving into areas of the screen. Must work with all apps, while my app in the background, etc.

I have set up a CGEventTap hook that has a callback for mouse movements.

The user's mouse movement continues to pass through the hook, no matter how I attempt to modify/kill the movement. That mirrors the experiences of others: https://mcmap.net/q/742556/-consuming-osx-mouse-trackpad-events-with-an-event-tap

- (CGEventRef) mouseMovedEvent:(CGEventRef) newUserMouseMovement
{ 
    //Attempt to modify the mouse movement
    CGEventSetDoubleValueField(newUserMouseMovement, kCGMouseEventDeltaX, 0);
    CGEventSetDoubleValueField(newUserMouseMovement, kCGMouseEventDeltaY, 0);
    CGEventSetDoubleValueField(newUserMouseMovement, kCGMouseEventDeltaX, 0.0);

    //Attempt to kill the event
    return NULL;
}
//Mouse movement still works normally.

I am able to use CGDisplayMoveCursorToPoint or CGWarpMouseCursorPosition to reposition the cursor back to the original position.

This works fine, although I would rather just kill the event altogether.

The problem is that the original user mouse movement shows the cursor visual at that point for a split second, before I am able to move the cursor.

I'm using:

CGSetLocalEventsSuppressionInterval(0.0);

to increase the frequency at which the Mouse movement fires. But that also makes the "real" cursor, before I move it, flash in the "forbidden area" if the user holds the mouse against the area in which I don't want the mouse to go.

I will potentially use: Globally hiding cursor (from background app) but I doubt that would be Mac App Store legal.

Any ideas?

EDIT: How I create the event tap:

eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);

...

    CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
    if (type == kCGEventMouseMoved) {
        event = [refToSelf mouseMovedEvent:event];
    }

    ...

    return event;
}
Brutify answered 28/3, 2012 at 0:21 Comment(7)
Can you show the arguments you're passing when you create the tap?Fat
Yeah, missed that... added now.Brutify
Great! Now, is this process running as root? You can't modify events at the HID->window server junction except as root.Fat
I assume running as root is not something I would want to do if the app is intended for distribution, especially via the Mac App Store... true? Let's not go down that path if it's not something that's usable by others.Brutify
Unfortunately, that's your Catch-22. You can't implement this unless your process runs as root, and your process can't run as root because the App Store won't allow it.Crosspurpose
Damn, that's unfortunate. Especially because it's very easy to eat key-press events.Brutify
I guess my next strategy would be to somehow optimize/buffer the mouse movements (with CGSetLocalEventsSuppressionInterval for example) to reduce the number of "ghost" cursors that appear.Brutify
F
2

You're trying to modify events at the kCGHIDEventTap location, which

Specifies that an event tap is placed at the point where HID system events enter the window server.

Unfortunately, the CGEventTapCreate() doc says:

Only processes running as the root user may locate an event tap at the point where HID events enter the window server; for other users, this function returns NULL.

I suspect this is strongly related to your difficulty, although the docs don't seem to match up with exactly what's happening (they are more than four years old).

Perhaps you can spin this functionality off into a separate process that has super-user permissions, leaving the rest of your app in normal user mode? I believe there's also a way to request root permissions for just a specific action taken by your program.

Fat answered 28/3, 2012 at 1:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.