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?