0 Replies
      Latest reply on Jul 1, 2019 3:31 AM by p-i-
      p-i- Level 1 Level 1 (0 points)

        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?