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

Swift状态栏应用如何检测Option键按下与抬起状态

问题描述

我开发了一款以NSStatusItem形式运行的Swift Cocoa应用,会在Mac右上角状态栏展示下拉菜单。我希望用户按住Option键打开状态栏项菜单时,展示额外的「高级」菜单项。目前我可以检测到Option键的按压事件,但无法判断按键当前是按下还是抬起状态。

以下是我当前在AppDelegate.swift中编写的代码:

func applicationDidFinishLaunching(_ aNotification: Notification) {
  NSEvent.addGlobalMonitorForEvents(matching: NSEvent.EventTypeMask.flagsChanged, handler: keyEvent);
}
    
func keyEvent(event: NSEvent) {
  if let event = NSApp.currentEvent {
    if event.modifierFlags.contains(.option) {
      print("option key up/down event")
    }
  }
}

这段代码可以在Option键按下、松开回弹时都打印提示信息,但问题是我无法判断任意时刻Option键的具体状态。

编辑说明:已有的同类实现方案要么逻辑过于复杂(需要添加定时器、运行循环观察者、零高度自定义视图),要么是通过创建菜单项alternates实现效果,仅支持菜单项的状态切换,无法满足本次添加额外菜单项的需求,相关实现思路可作为同类问题的参考。

实现方案

无法直接通过单次flagsChanged事件判断按键是按下还是抬起,本质原因是这类事件只回调当前触发时的修饰键状态集合,需要自行记录上一次Option键的状态,通过新旧状态比对区分动作,同时存储实时状态供全局读取。

具体修改步骤

  1. 在AppDelegate中添加属性存储Option键的实时状态
var isOptionKeyPressed: Bool = false
  1. 替换原有事件监听逻辑,同时添加全局+本地事件监听(补全应用前台时的事件监听能力),在回调中做状态比对
func applicationDidFinishLaunching(_ aNotification: Notification) {
    // 监听应用外的修饰键事件
    NSEvent.addGlobalMonitorForEvents(matching: .flagsChanged, handler: keyEvent)
    // 监听应用内的修饰键事件,否则应用在前台时收不到回调
    NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event in
        self?.keyEvent(event: event)
        return event
    }
}

func keyEvent(event: NSEvent) {
    // 直接使用回调传入的事件判断当前Option键状态,不要用NSApp.currentEvent避免取错事件
    let currentOptionState = event.modifierFlags.contains(.option)
    // 状态无变化时直接返回,避免重复触发
    guard isOptionKeyPressed != currentOptionState else { return }
    // 更新存储的实时状态
    isOptionKeyPressed = currentOptionState
    
    if isOptionKeyPressed {
        print("Option键按下")
        // 可在此处触发展示高级菜单项的预逻辑
    } else {
        print("Option键抬起")
        // 可在此处触发隐藏高级菜单项的逻辑
    }
}

注意事项

  • 存储的isOptionKeyPressed属性就是任意时刻可直接读取的Option键实时状态,在菜单打开前读取该值,即可决定是否插入额外的高级菜单项。
  • 可以额外给状态栏菜单绑定NSMenuDelegate,在menuWillOpen(_:)回调中再次校验NSApp.currentEvent?.modifierFlags.contains(.option)的状态,避免极端场景下事件监听漏判。
  • 不要依赖NSApp.currentEvent在全局事件回调中做判断,回调参数传入的event才是当前触发修饰键变化的对应事件,判断结果更可靠。

内容的提问来源于stack exchange,提问作者fsctl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:06:36