Я пытаюсь переназначить свой 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;
:
По большей части это работает. Однако часто я замечаю скольжение / скольжение мыши, как хождение по льду. Есть небольшое ухудшение производительности.
Кто-нибудь захочет критиковать этот подход?
Интересно, есть ли небольшая проблема округления до целого в dx
, dy
. Или если события как-то теряются.
Может быть, небезопасно получить 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 )