macOS菜单栏鼠标锁定App:如何检测Control+U+L快捷键退出?
解决方案
1. 修正事件掩码
当前代码的CGEventMask仅包含鼠标事件,必须添加键盘事件掩码才能捕获按键操作:
void lockTrackpad(void) { CGEventMask mask = ( // 鼠标事件掩码 CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseUp) | CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventRightMouseUp) | CGEventMaskBit(kCGEventRightMouseDown) | CGEventMaskBit(kCGEventScrollWheel) // 新增键盘事件掩码 | CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) ); eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, CGEventCallback_r, nil); // 将事件Tap加入RunLoop(缺失的关键步骤) if (eventTap) { CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); CFRelease(runLoopSource); CGEventTapEnable(eventTap, true); CFRunLoopRun(); } }
2. 实现组合键检测逻辑
需要全局变量跟踪按键状态,因为单个事件只能捕获单个按键动作:
// 全局变量记录按键按下状态 static bool isControlPressed = false; static bool isUPressed = false; static bool isLPressed = false; // 定义对应按键的KeyCode #define KEY_CONTROL_LEFT 59 #define KEY_CONTROL_RIGHT 62 #define KEY_U 32 #define KEY_L 37
回调函数中处理按键状态更新与组合键判断:
CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { // 处理键盘事件 if (type == kCGEventKeyDown || type == kCGEventKeyUp) { CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); bool isKeyDown = (type == kCGEventKeyDown); // 更新按键状态 switch (keycode) { case KEY_CONTROL_LEFT: case KEY_CONTROL_RIGHT: isControlPressed = isKeyDown; break; case KEY_U: isUPressed = isKeyDown; break; case KEY_L: isLPressed = isKeyDown; break; default: // 其他按键按下时重置U/L状态,避免误触发 if (isKeyDown) { isUPressed = false; isLPressed = false; } break; } // 检测Control+U+L同时按下的条件 if (isControlPressed && isUPressed && isLPressed) { printf("pressed control + U + L\n"); doSomething(); // 重置状态,防止重复触发 isUPressed = false; isLPressed = false; } } // 拦截所有鼠标事件,不向下传递 if (type >= kCGEventMouseMoved && type <= kCGEventScrollWheel) { return nil; } // 键盘事件正常传递(如需拦截可返回nil) return event; }
3. 优雅退出应用
避免直接使用exit(),改为停止事件Tap并退出RunLoop:
void doSomething(void) { // 禁用并释放事件Tap if (eventTap) { CGEventTapEnable(eventTap, false); CFRelease(eventTap); eventTap = NULL; } // 退出RunLoop,结束应用 CFRunLoopStop(CFRunLoopGetCurrent()); }
沙箱环境配置
- 在项目
Entitlements文件中添加输入设备权限:
<key>com.apple.security.device.input</key> <true/>
- 引导用户开启辅助功能权限:系统偏好设置→安全性与隐私→隐私→辅助功能,勾选你的应用。可通过
AXIsProcessTrusted()检查权限,AXRequestProcessTrusted()主动请求授权。
内容的提问来源于stack exchange,提问作者Ömürcan Cengiz
相关产品推荐
相关产品推荐

