如何在MacOS上模拟鼠标拖动?

时间:2019-07-01 12:51:47

标签: nsevent

我正尝试使用以下方式将LeftMouse重新映射为CTRL

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;    
                :

在大多数情况下这是可行的。但是,我经常注意到鼠标滑行/滑行,就像在冰上行走一样。性能略有下降。

有人愿意批评这种方法吗?

我想知道dxdy中是否存在一些细微的四舍五入问题。或者,如果事件以某种方式迷失了。

prev_mouse获取[NSEvent mouseLocation]也许是不安全的?

我无法获得当前的鼠标位置有点烦人。我猜想[NSEvent mouseLocation]仅在NSEventTypeMouseMoved事件完成后得到更新。如果我只能访问新的当前位置,则可以省去/* awkward multi-screen bounds checking here */

另一种方法是执行以下操作的定期计时器:

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);
       }];

可以将这种方法提炼成可用的东西吗?

什么是正确的方法?

(也发布在Apple Dev Forums上)

0 个答案:

没有答案