Ich fügte allen meinen NSWindow
Veranstaltungen einen Tipp hinzu . Es stellt sich heraus, dass der Master Swipe-Events simuliert!
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= 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= 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= 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=
OK, das ist ziemlich schlau, denn es bedeutet im Grunde, dass es in jeder Ansicht funktioniert, die den swipeWithEvent:
Selektor unterstützt . Ich habe keine Ahnung, warum dies nicht das Standardverhalten für die seitlichen Tasten ist! Jetzt muss ich herausfinden, wie ich diese Funktionalität zu meinen anderen Mäusen hinzufügen kann. Ich glaube nicht, dass USB Overdrive so etwas tun kann, es sei denn, AppleScript kann Gesten simulieren.
UPDATE: Es ist mir gelungen, diese Ereignisse mithilfe der Reverse-Engineering-Gesten-Simulationsfunktionen von Natevw zu replizieren ( https://github.com/calftrail/Touch) . Möglicherweise muss noch etwas repariert werden, aber es funktioniert! Der letzte Schritt wird die Erstellung einer ständig laufenden App sein, die M4- und M5-Ereignisse aufnimmt und diese Gesten ausspuckt.
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: Hier ist eine grobe Arbeitsskizze eines View Controllers, der M4 und M5 global erfasst und Wischbewegungen ausgibt.
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: Ich habe eine Open-Source-Menüleisten-App veröffentlicht, die das Verhalten des Masters für alle Mäuse von Drittanbietern repliziert. Es heißt SensibleSideButtons . Die technischen Details sind auf der Website beschrieben.