OSX 中的通用后退/前进鼠标按钮而不是 M4/M5?

OSX 中的通用后退/前进鼠标按钮而不是 M4/M5?

我对我的 Logitech MX Master 鼠标上两个侧键的行为感到困惑。在我所有的其他鼠标上,侧键被检测为通用的“按钮 4”和“按钮 5”。(我使用 Xcode 验证了这一点。)与 Windows 不同,OS X 似乎将这些命令视为鼠标中键单击,因此为了获得您可能期望的后退/前进行为,您需要使用 USB Overdrive 之类的工具将它们映射到+[+ ]。不幸的是,这种解决方法并不适用于每个应用程序,当您触发它时,菜单栏会闪烁。

同时,我的 Xcode 鼠标点击根本检测不到 Master 上的侧边按钮,但它们在几乎所有带有导航栏的应用程序中都能正常工作。我在 Finder、Safari、系统偏好设置和 Xcode 中测试了它们。没有菜单闪烁,鼠标光标必须位于导航栏控制的窗口区域上方,这意味着发送了某种通用的后退/前进事件(与通常的 M4/M5 相反)。但是,我找不到 OS X 中存在此类事件的文档。大多数 M4/M5 修复都涉及将这些按钮映射到+[+ ]

那么 Master 用这些侧面按钮做什么呢?我如何在我所有的其他鼠标上复制相同的行为?

答案1

VS Code 现在支持Go BackGo Forward操作,包括默认键绑定分别为CTRL+-CTRL++ SHIFT-

我可以配置 Logi Options 以使用这些快捷方式,而不会破坏其他应用程序,方法是:

  1. All Applications通过-> Add Application->添加 VS Code 配置文件Other...,然后搜索“Visual Studio Code”
  2. 将后退和前进按钮重新映射到Keystroke assignment,其键序列与 VS Code 键绑定相匹配

选择了配置文件后,后退按钮配置如下所示:

Logi 选项,已选择 Visual Studio Code 配置文件

经过这些更改后,前进和后退按钮可以在 VS Code 中使用,并且其他应用(如 Chrome)中的导航不受影响。

答案2

我添加了一个水龙头全部我的NSWindow事件。结果……Master 正在模拟滑动事件!

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}

好的,这很聪明,因为它基本上意味着它可以在任何支持swipeWithEvent:选择器的视图中工作。我不知道为什么这不是侧边按钮的默认行为!现在我必须弄清楚如何将此功能添加到我的其他鼠标中。我不认为 USB Overdrive 可以做这样的事情……除非 AppleScript 有办法模拟手势。

更新:我已经设法使用复制这些事件娜泰夫逆向工程的手势模拟功能,https://github.com/calftrail/Touch。可能仍需要进行一些修复,但它已经可以正常工作了!最后一步是创建一个始终运行的应用程序,该应用程序会处理 M4 和 M5 事件并输出这些手势。

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

更新2:下面是一个视图控制器的粗略工作草图,它可以全局捕获 M4 和 M5 并发出滑动。

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

更新 3:我发布了一款开源菜单栏应用,它可以为所有第三方鼠标复制 Master 的行为。它叫做SensibleSideButtons。技术细节已在网站上描述。

相关内容