Eu adicionei um toque em todos meus NSWindow
eventos. Acontece que ... o Mestre está simulando eventos de furto!
NSEvent: type=Swipe loc=(252,60) time=5443.9 flags=0x100 win=0x100b091f0 winNum=2014 ctxt=0x0 phase: 1 axis:0 amount=0.000 velocity={0, 0}
NSEvent: type=Swipe loc=(252,60) time=5443.9 flags=0x100 win=0x100b091f0 winNum=2014 ctxt=0x0 phase: 8 axis:0 amount=0.000 velocity={0, 0}
NSEvent: type=Swipe loc=(252,60) time=5445.7 flags=0x100 win=0x100b091f0 winNum=2014 ctxt=0x0 phase: 1 axis:0 amount=0.000 velocity={0, 0}
NSEvent: type=Swipe loc=(252,60) time=5445.7 flags=0x100 win=0x100b091f0 winNum=2014 ctxt=0x0 phase: 8 axis:0 amount=0.000 velocity={0, 0}
OK, isso é muito inteligente, já que basicamente significa que funcionará em qualquer visualização que suporte o seletor swipeWithEvent:
. Eu não tenho idéia porque este não é o comportamento padrão para os botões laterais! Agora tenho que descobrir como adicionar essa funcionalidade aos meus outros mouses. Eu não acho que o USB Overdrive possa fazer algo assim ... a menos que o AppleScript tenha uma maneira de simular gestos.
UPDATE: consegui replicar esses eventos usando a engenharia reversa do natevw funções de simulação de gestos, link . Talvez ainda precise ser consertado um pouco, mas funciona! O passo final será criar um aplicativo que funcione sempre e que coma eventos M4 e M5 e gere esses gestos.
TLInfoSwipeDirection dir = kTLInfoSwipeLeft;
NSDictionary* swipeInfo1 = [NSDictionary dictionaryWithObjectsAndKeys:
@(kTLInfoSubtypeSwipe), kTLInfoKeyGestureSubtype,
@(1), kTLInfoKeyGesturePhase,
nil];
NSDictionary* swipeInfo2 = [NSDictionary dictionaryWithObjectsAndKeys:
@(kTLInfoSubtypeSwipe), kTLInfoKeyGestureSubtype,
@(dir), kTLInfoKeySwipeDirection,
@(4), kTLInfoKeyGesturePhase,
nil];
CGEventRef event1 = tl_CGEventCreateFromGesture((__bridge CFDictionaryRef)(swipeInfo1), (__bridge CFArrayRef)@[]);
CGEventRef event2 = tl_CGEventCreateFromGesture((__bridge CFDictionaryRef)(swipeInfo2), (__bridge CFArrayRef)@[]);
CGEventPost(kCGHIDEventTap, event1);
CGEventPost(kCGHIDEventTap, event2);
// not sure if necessary under ARC
CFRelease(event1);
CFRelease(event2);
UPDATE 2: Aqui está um esboço de trabalho de um Controlador de Visão que captura globalmente M4 e M5 e emite furtos.
static void SBFFakeSwipe(TLInfoSwipeDirection dir) {
NSDictionary* swipeInfo1 = [NSDictionary dictionaryWithObjectsAndKeys:
@(kTLInfoSubtypeSwipe), kTLInfoKeyGestureSubtype,
@(1), kTLInfoKeyGesturePhase,
nil];
NSDictionary* swipeInfo2 = [NSDictionary dictionaryWithObjectsAndKeys:
@(kTLInfoSubtypeSwipe), kTLInfoKeyGestureSubtype,
@(dir), kTLInfoKeySwipeDirection,
@(4), kTLInfoKeyGesturePhase,
nil];
CGEventRef event1 = tl_CGEventCreateFromGesture((__bridge CFDictionaryRef)(swipeInfo1), (__bridge CFArrayRef)@[]);
CGEventRef event2 = tl_CGEventCreateFromGesture((__bridge CFDictionaryRef)(swipeInfo2), (__bridge CFArrayRef)@[]);
CGEventPost(kCGHIDEventTap, event1);
CGEventPost(kCGHIDEventTap, event2);
CFRelease(event1);
CFRelease(event2);
}
static CGEventRef KeyDownCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
int64_t number = CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber);
BOOL down = (CGEventGetType(event) == kCGEventOtherMouseDown);
if (number == 3) {
if (down) {
SBFFakeSwipe(kTLInfoSwipeLeft);
}
return NULL;
}
else if (number == 4) {
if (down) {
SBFFakeSwipe(kTLInfoSwipeRight);
}
return NULL;
}
else {
return event;
}
}
@implementation ViewController
-(void) viewDidLoad {
[super viewDidLoad];
NSDictionary* options = @{ (__bridge id)kAXTrustedCheckOptionPrompt: @YES };
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
assert(accessibilityEnabled);
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventOtherMouseUp)|CGEventMaskBit(kCGEventOtherMouseDown),
&KeyDownCallback,
NULL);
assert(eventTap != NULL);
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(NULL, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CFRelease(runLoopSource);
CGEventTapEnable(eventTap, true);
//CFRelease(eventTap); -- needs to be done on dealloc, I think
}
@end
UPDATE 3: eu lancei um aplicativo de barra de menu de código aberto que replica o comportamento do mestre para todos os mouses de terceiros. É chamado de SensibleSideButtons . Os detalhes técnicos estão descritos no site.