Swift中如何在App获焦点时跨所有窗口监听NSEvent
在macOS App获焦时全局监听按键(多窗口场景)
核心方案
直接利用NSApplication的本地事件监听机制,在App层面拦截所有按键事件——当App处于活跃状态(获焦)时,所有按键事件会先经过这个监听,无需为每个窗口/视图单独配置,完美覆盖多窗口场景。
实现步骤
- 在
AppDelegate中注册本地事件监听器,指定监听keyDown(或keyUp)事件; - 实现事件处理逻辑,按需处理普通按键或组合键;
- 控制事件是否继续传递给窗口/视图(返回原事件则传递,返回
nil则截断)。
Swift 代码示例
import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // 注册本地按键事件监听,仅在App活跃时触发 NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in self.handleKeyDown(event) // 返回event让后续窗口/视图处理,返回nil则截断事件 return event } } private func handleKeyDown(_ event: NSEvent) { // 获取按键字符(忽略修饰键)和修饰键组合 let keyChar = event.charactersIgnoringModifiers ?? "" let modifiers = event.modifierFlags.intersection(.deviceIndependentFlagsMask) print("按键: \(keyChar) | 修饰键: \(modifiers)") // 示例:处理Command+C组合键 if modifiers.contains(.command) && keyChar == "c" { print("捕获到Command+C") // 若要阻止系统默认复制行为,可将上方return event改为return nil } // 示例:处理方向键(通过keyCode判断) switch event.keyCode { case 123: print("左方向键") case 124: print("右方向键") default: break } } }
Objective-C 代码示例
#import "AppDelegate.h" @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // 注册本地按键事件监听 [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { [self handleKeyDown:event]; return event; // 返回事件让后续处理,nil则截断 }]; } - (void)handleKeyDown:(NSEvent *)event { NSString *keyChar = [event charactersIgnoringModifiers]; NSEventModifierFlags modifiers = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; NSLog(@"按键: %@ | 修饰键: %lu", keyChar, (unsigned long)modifiers); // 处理Command+C组合键 if ((modifiers & NSEventModifierFlagCommand) && [keyChar isEqualToString:@"c"]) { NSLog(@"捕获到Command+C"); } // 处理方向键 switch (event.keyCode) { case 123: NSLog(@"左方向键"); break; case 124: NSLog(@"右方向键"); break; default: break; } } @end
关键说明
- 无需系统权限:
addLocalMonitorForEvents是App内部监听,仅对当前App生效,不需要 accessibility 权限(区别于全局系统监听); - 事件传递控制:返回原事件可让窗口/视图继续处理默认逻辑,返回
nil则完全拦截事件; - 支持多事件类型:可修改
matching参数监听.keyUp等其他事件类型。
内容的提问来源于stack exchange,提问作者gcstr
相关产品推荐
相关产品推荐

