MacOS下使用CGEventSetIntegerValueField反转鼠标X轴无效问题
我尝试在MacOS上反转Magic Trackpad 2的X轴移动,据了解需要监听NSEventMaskMouseMoved并在callback中进行修改,以下是我的代码:
#import <Foundation/Foundation.h> #import <CoreGraphics/CoreGraphics.h> #import <CoreFoundation/CoreFoundation.h> #import <AppKit/AppKit.h> static CGEventRef callback(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, void *userInfo) { if (type == kCGEventMouseMoved) { // 获取原始Delta X值 int64_t deltaX = CGEventGetIntegerValueField(eventRef, kCGMouseEventDeltaX); // 反转Delta X值 int64_t invertedDeltaX = -deltaX; // 将反转后的Delta X值设置回原事件 CGEventSetIntegerValueField(eventRef, kCGMouseEventDeltaX, invertedDeltaX); NSLog(@"Original Delta X: %lld", deltaX); NSLog(@"Inverted Delta X: %lld", invertedDeltaX); return eventRef; } return eventRef; } int main(int argc, const char * argv[]) { @autoreleasepool { CFMachPortRef tapPort = (CFMachPortRef)CGEventTapCreate(kCGSessionEventTap, kCGTailAppendEventTap, kCGEventTapOptionDefault, NSEventMaskMouseMoved, callback, nil); if (tapPort) { NSLog(@"tapPort created %p", tapPort); CFRunLoopSourceRef tapSource = (CFRunLoopSourceRef)CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tapPort, 0); if (tapSource) { NSLog(@"tapSource created %p", tapSource); CFRunLoopAddSource(CFRunLoopGetMain(), tapSource, kCFRunLoopCommonModes); // CGEventTapEnable(tapSource, true); CFRunLoopRun(); } else { NSLog(@"tapSource NOT created"); } } else { NSLog(@"tapPort NOT created"); } } return 0; }
日志控制台显示一切正常(已授予Accessibility权限),但鼠标移动事件并未改变,似乎CGEventSetIntegerValueField没有起到作用。请问我是不是操作方式有误?
你的代码存在几个关键问题,导致修改后的事件没有被系统正确处理:
1. 事件插入位置错误
你使用了kCGTailAppendEventTap,这会把你的事件tap添加到现有tap队列的末尾,意味着系统已经处理完原始事件后才会执行你的回调,修改后的事件不会影响系统的指针移动逻辑。
修正: 将kCGTailAppendEventTap改为kCGHeadInsertEventTap,让你的回调在系统处理事件之前执行,这样修改后的事件会被系统处理。
2. 事件掩码不完整
仅监听kCGEventMouseMoved不足以覆盖Trackpad的所有指针移动场景(比如拖拽操作时的kCGEventLeftMouseDragged、kCGEventRightMouseDragged等),导致部分移动行为没有被反转。
修正: 使用完整的鼠标移动相关事件掩码:
CGEventMask eventMask = CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged);
然后在CGEventTapCreate中传入这个eventMask,替换原来的NSEventMaskMouseMoved。
3. CGEventTapEnable的参数错误且未启用
你注释掉了CGEventTapEnable,并且参数错误(应该传入tapPort而非tapSource),这会导致事件tap可能未正确启用。
修正: 取消注释该行,并修正参数:
CGEventTapEnable(tapPort, true);
修正后的完整代码
#import <Foundation/Foundation.h> #import <CoreGraphics/CoreGraphics.h> #import <CoreFoundation/CoreFoundation.h> #import <AppKit/AppKit.h> static CGEventRef callback(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, void *userInfo) { // 处理所有鼠标移动/拖拽事件 if (type == kCGEventMouseMoved || type == kCGEventLeftMouseDragged || type == kCGEventRightMouseDragged || type == kCGEventOtherMouseDragged) { // 获取原始Delta X值 int64_t deltaX = CGEventGetIntegerValueField(eventRef, kCGMouseEventDeltaX); // 反转Delta X值 int64_t invertedDeltaX = -deltaX; // 将反转后的Delta X值设置回原事件 CGEventSetIntegerValueField(eventRef, kCGMouseEventDeltaX, invertedDeltaX); NSLog(@"Original Delta X: %lld", deltaX); NSLog(@"Inverted Delta X: %lld", invertedDeltaX); } return eventRef; } int main(int argc, const char * argv[]) { @autoreleasepool { // 定义完整的鼠标移动事件掩码 CGEventMask eventMask = CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged); CFMachPortRef tapPort = (CFMachPortRef)CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, // 改为头部插入 kCGEventTapOptionDefault, eventMask, // 使用完整掩码 callback, nil); if (tapPort) { NSLog(@"tapPort created %p", tapPort); CFRunLoopSourceRef tapSource = (CFRunLoopSourceRef)CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tapPort, 0); if (tapSource) { NSLog(@"tapSource created %p", tapSource); CFRunLoopAddSource(CFRunLoopGetMain(), tapSource, kCFRunLoopCommonModes); CGEventTapEnable(tapPort, true); // 启用tap,参数修正为tapPort CFRunLoopRun(); } else { NSLog(@"tapSource NOT created"); } } else { NSLog(@"tapPort NOT created"); } } return 0; }
内容的提问来源于stack exchange,提问作者Martin Pham

