Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is CGWarpMouseCursorPosition causing a delay? If it is not, what is?

I have code here that restricts the mouse to a region on the screen, it is working relatively well, with only one big problem. The mouse doesn't get moved cleanly/smoothly when running along the edges of the area, it instead jumps in a very choppy manner, I believe this might be due to CGWarpMouseCursorPosition causing a delay upon each "warp".

Can anyone tell if it's something in my code that is causing this delay, or if it is in fact the mouse warp function. If it is the mouse warp function, is there any way I can get a smooth relocation of the mouse? I've done the same thing in flash and it works flawlessly, I know that the loop isn't just taking so much time to execute that it's slowing things down because it only runs maybe 4 or 5 times.

CGEventRef 
mouse_filter(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {


    CGPoint point = CGEventGetLocation(event);

    float tX = point.x;
    float tY = point.y;

    if( tX <= 700 && tX >= 500 && tY <= 800 && tY >= 200){
        // target is inside O.K. area, do nothing
    }else{

    CGPoint target; 

    //point inside restricted region:
    float iX = 600; // inside x
    float iY = 500; // inside y

    // delta to midpoint between iX,iY and tX,tY
    float dX;
    float dY;

    float accuracy = .5; //accuracy to loop until reached

    do {
        dX = (tX-iX)/2;
        dY = (tY-iY)/2;

        if((tX-dX) <= 700 && (tX-dX) >= 500 && (tY-dY) <= 800 && (tY-dY) >= 200){
            iX += dX;
            iY += dY;
        } else {
            tX -= dX;
            tY -= dY;
        }

    } while (abs(dX)>accuracy || abs(dY)>accuracy);

        target = CGPointMake(roundf(tX), roundf(tY));
        CGWarpMouseCursorPosition(target);

    }



    return event;
}

int
main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    CFRunLoopSourceRef runLoopSource;
    CGEventMask event_mask;
    event_mask = CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged);

    CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, event_mask, mouse_filter, NULL);

    if (!eventTap) {
        NSLog(@"Couldn't create event tap!");
        exit(1);
    }

    runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

    CGEventTapEnable(eventTap, true);

    CFRunLoopRun();

    CFRelease(eventTap);
    CFRelease(runLoopSource);
    [pool release];

    exit(0);
}
like image 611
BumbleShrimp Avatar asked Nov 21 '11 16:11

BumbleShrimp


3 Answers

As you discovered, CGSetLocalEventsSuppressionInterval fixes your problem.

However, it's deprecated as of 10.6. the Apple docs state:

This function is not recommended for general use because of undocumented special cases and undesirable side effects. The recommended replacement for this function is CGEventSourceSetLocalEventsSuppressionInterval, which allows the suppression interval to be adjusted for a specific event source, affecting only events posted using that event source.

Unfortunately, the replacementCGEventSourceSetLocalEventsSuppressionInterval does not work with CGWarpMouseCursorPosition movements.

Instead, use CGAssociateMouseAndMouseCursorPosition(true) immediately after the warp:

CGPoint warpPoint = CGPointMake(42, 42);
CGWarpMouseCursorPosition(warpPoint);
CGAssociateMouseAndMouseCursorPosition(true);

The documentation makes no mention of this behavior, but it appears to cancel the suppression interval after the warp.

like image 126
ck_ Avatar answered Dec 04 '22 18:12

ck_


I could get CGEventSourceSetLocalEventsSuppressionInterval to work with CGWarpMouseCursorPosition the following way:

auto eventSourceRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
CGEventSourceSetLocalEventsSuppressionInterval(eventSourceRef, 0);

This works fine with CGWarpMouseCursorPosition (and is not deprecated), whereas CGAssociateMouseAndMouseCursorPosition(true) was of no help for me.

like image 26
spacemike Avatar answered Dec 04 '22 20:12

spacemike


You're probably looking for CGSetLocalEventsSuppressionInterval(), a method deprecated as of 10.6... it still works though in 10.7.

http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/c/func/CGSetLocalEventsSuppressionInterval

like image 40
weather Avatar answered Dec 04 '22 18:12

weather