Remap LeftMouseButton -- simulating drag

I'm attempting to remap my LeftMouse to CTRL using:


CGPoint mouseFlip( CGPoint pt ) {

return CGPointMake(pt.x, [NSScreen mainScreen].frame.size.height - pt.y);

}


_eventTap = CGEventTapCreate(

kCGHIDEventTap,

kCGHeadInsertEventTap,

kCGEventTapOptionDefault,

CGEventMaskBit(NSEventTypeMouseMoved) | CGEventMaskBit(NSEventTypeFlagsChanged),

(CGEventTapCallBack)_tapCallback,

(__bridge void *)(self)

);

:

CGEventRef _tapCallback(

CGEventTapProxy proxy,

CGEventType type,

CGEventRef event,

Intercept* listener

)

{

//Do not make the NSEvent here.

//NSEvent will throw an exception if we try to make an event from the tap timout type

@autoreleasepool {

if( type == kCGEventTapDisabledByTimeout ) {

NSLog(@"event tap has timed out, re-enabling tap");

[listener tapEvents];

return nil;

}

if( type != kCGEventTapDisabledByUserInput ) {

return [listener processEvent:event];

}

}

return event;

}



- (CGEventRef)processEvent:(CGEventRef)cgEvent

{

NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];


switch( event.type ) {

case NSEventTypeMouseMoved:

CGPoint prev_mouse = [NSEvent mouseLocation];


int64_t dx = CGEventGetIntegerValueField(cgEvent, kCGMouseEventDeltaX);

int64_t dy = CGEventGetIntegerValueField(cgEvent, kCGMouseEventDeltaY);


CGPoint new_mouse = {

prev_mouse.x + dx,

prev_mouse.y - dy

};

:

/* awkward multi-screen bounds checking here */

:

CGEventRef dragEvent = CGEventCreateMouseEvent(

NULL,

kCGEventLeftMouseDragged,

mouseFlip(new_mouse),

0

);

CGEventPost(kCGHIDEventTap, dragEvent);

CFRelease(dragEvent);


break;

:


For the most part this works. However often I notice the mouse slips/glides, like walking on ice. There is some subtle deterioration in performance.


Would anyone be willing to critique this approach?


I wonder if there is some subtle round-to-int issue in dx,dy. Or if events are getting lost somehow.


Maybe it's not safe to get `prev_mouse` from `[NSEvent mouseLocation]`?


It's kind of annoying that I can't get the CURRENT mouse location. I'm guessing `[NSEvent mouseLocation]` only get updated AFTER the `NSEventTypeMouseMoved` event completes. If I could only access the new current location, I could dispense with the /* awkward multi-screen bounds checking here */.


An alternative approach would be a periodic timer that does:


```

timer = [NSTimer scheduledTimerWithTimeInterval: .01f

repeats: YES

block:

^(NSTimer *timer) {

if( ! self->ctrl_is_down )

return;



CGEventRef dragEvent = CGEventCreateMouseEvent(

NULL,

kCGEventLeftMouseDragged,

mouseFlip( [NSEvent mouseLocation] ),

0

);

CGEventPost(kCGHIDEventTap, dragEvent);

CFRelease(dragEvent);

}];

```


Can this approach be refined into something usable?


What's the right way to do this?