You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

沙箱环境配置

  1. 在项目Entitlements文件中添加输入设备权限:
<key>com.apple.security.device.input</key>
<true/>
  1. 引导用户开启辅助功能权限:系统偏好设置→安全性与隐私→隐私→辅助功能,勾选你的应用。可通过AXIsProcessTrusted()检查权限,AXRequestProcessTrusted()主动请求授权。

内容的提问来源于stack exchange,提问作者Ömürcan Cengiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:45:34