macOS SwiftUI应用如何拦截电源键按压事件?已实现键盘拦截
拦截MacBook电源键事件的解决方案
你的问题核心在于电源键属于系统级HID(人机接口设备)事件,CGEventTap仅能捕获常规键盘/鼠标输入事件,无法触及这类底层硬件事件。要实现电源键拦截,需要借助IOKit框架直接与HID设备交互。
实现步骤
1. 添加IOKit框架依赖
在Xcode项目中,进入「Build Phases」>「Link Binary With Libraries」,添加IOKit.framework。
2. 实现HID电源键监视器
在你的EventMonitor类中添加以下代码,用于捕获电源键事件并阻止系统响应:
import IOKit.hid private var hidManager: IOHIDManager? private func startPowerKeyMonitoring() { hidManager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone)) // 匹配MacBook电源键对应的HID设备 let matchingDict: [CFString: Any] = [ kIOHIDDeviceUsagePageKey: kHIDPage_GenericDesktop, kIOHIDDeviceUsageKey: kHIDUsage_GD_SystemPowerDown ] IOHIDManagerSetDeviceMatching(hidManager!, matchingDict as CFDictionary) // 注册设备连接回调 IOHIDManagerRegisterDeviceMatchingCallback(hidManager!, { manager, _, sender in let devices = IOHIDManagerCopyDevices(manager).takeRetainedValue() as [IOHIDDevice] guard let powerKeyDevice = devices.first else { return } // 注册电源键事件回调 IOHIDDeviceRegisterInputValueCallback(powerKeyDevice, { _, context, _, _, value in guard let event = value?.pointee else { return } // 取消事件,阻止系统处理睡眠/关机逻辑 IOHIDEventSetCanceled(event, true) // 结合你的监控状态判断是否拦截 guard let selfRef = Unmanaged<EventMonitor>.fromOpaque(context!).takeUnretainedValue() else { return } if selfRef.isMonitoring { // 电源键已被拦截,可添加自定义处理逻辑 } }, Unmanaged.passUnretained(self).toOpaque()) // 打开设备以接收事件 IOHIDDeviceOpen(powerKeyDevice, IOOptionBits(kIOHIDOptionsTypeNone)) }, Unmanaged.passUnretained(self).toOpaque()) // 将HID管理器绑定到当前RunLoop IOHIDManagerScheduleWithRunLoop(hidManager!, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) IOHIDManagerOpen(hidManager!, IOOptionBits(kIOHIDOptionsTypeNone)) } private func stopPowerKeyMonitoring() { guard let manager = hidManager else { return } IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone)) hidManager = nil }
3. 整合现有监控逻辑
修改你的startKeyboardMonitoring方法,同步启动电源键监控:
private func startKeyboardMonitoring() { // 原有的CGEventTap代码保持不变... // 启动电源键监控 startPowerKeyMonitoring() }
同时在停止监控的逻辑中添加电源键监视器的停止操作:
if isKeyComboPressed && !lastKeyComboState { DispatchQueue.main.async { self.isMonitoring.toggle() if !self.isMonitoring { self.stopPowerKeyMonitoring() } else { self.startPowerKeyMonitoring() } } }
关键注意事项
- 权限要求:应用必须获得「辅助功能」权限(系统偏好设置 > 安全性与隐私 > 隐私 > 辅助功能,勾选你的应用),否则无法拦截任何系统级事件。
- 设备兼容性:部分Mac机型的电源键HID匹配规则可能略有差异,若上述代码无法捕获事件,可尝试将
kHIDUsage_GD_SystemPowerDown替换为kHIDUsage_GD_SystemPower,或添加设备厂商ID过滤。 - 沙箱限制:若应用开启了App Sandbox,需关闭沙箱功能,或向苹果申请
com.apple.security.device.hid特殊权限(普通开发者较难通过)。
内容的提问来源于stack exchange,提问作者Lin Chen
相关产品推荐
相关产品推荐

