tags:

views:

734

answers:

2

I'm developing an extension to MATLAB's PsychToolbox that allows for better control of the mouse during psychophysical experiments (specifically, preventing the screen boundaries from limiting drag operations... it should feel like you can move the mouse "infinitely" in all directions). Since MATLAB doesn't support the creation of additional threads (and that would be needlessly complicated for this situation anyway), I can't make use of either the Carbon or Cocoa event managers.

CGGetLastMouseDelta is almost perfect for what I need to do (it gets me the amount the mouse has moved "since the last mouse movement event received by the application" ignoring screen boundaries), however there is one slight problem. When moving the mouse programatically (using either CGWarpMouseCursorPosition or CGDisplayMoveCursorToPoint), no events are generated. Therefore, CGGetLastMouseDelta doesn't seem to be aware that the mouse has moved at all. In other words, if I move the mouse 50 pixels over and 50 pixels down programatically, CGGetLastMouseDelta returns (0, 0) afterwards for the mouse delta. This is undesirable behavior in my context, and requires ugly workarounds. I've tried moving the mouse by posting events through the event system, as follows (this is a "mexFunction", MATLAB's way of calling C code):

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    CGEventRef event;
    CGPoint offset;
    CGPoint currentLocation;
    CGPoint newLocation;

    if (nrhs != 2)
        mexErrMsgTxt("The global x and y coordinates (and only those) must be supplied.");

    event = CGEventCreate(NULL);
    currentLocation = CGEventGetLocation(event);
    CFRelease(event);

    offset = CGPointMake((CGFloat) mxGetScalar(prhs[0]), (CGFloat) mxGetScalar(prhs[1]));
    newLocation = CGPointMake(currentLocation.x + offset.x, currentLocation.y + offset.y);

    event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, newLocation, kCGMouseButtonLeft);
    CGEventPost(kCGHIDEventTap, event);
    CFRelease(event);
}

This happily moves the mouse, but doesn't seem to change the behavior of CGGetLastMouseDelta at all. Does anybody know the exact specifications regarding what is returned by CGGetLastMouseDelta (and when?). Apple's documentation on on this stuff (the Quartz reference) is as usual close to useless (or at least, lacking in necessary details).

Thanks!

+2  A: 

A good idea might be to use CGAssociateMouseAndMouseCursorPosition(0) to disconnect mouse movement from the cursor. Then you don't get the problem with screen boundaries.

kotlinski
A: 

Option (1) Generate your own event which specifies that you caused the mouse to move.
Option (2) Call your mouse moved event handler function from the I moved the mouse routine.

codeDr