macOS应用中实现点击窗口全屏的最优方案
实现点击Mac窗口触发全屏的最优方案
针对你的需求,最优方案是基于Quartz Event Services捕获全局鼠标点击事件,结合AppKit API定位目标窗口并触发全屏操作,核心逻辑如下:
关键步骤
- 扩展现有全局事件监听,新增鼠标左键点击捕获(需系统辅助功能权限)
- 通过点击坐标匹配对应窗口的
windowNumber - 定位目标窗口所属的应用实例,调用全屏切换接口
具体代码实现
1. 权限检查(必须前置)
全局事件监听需要系统辅助功能权限,先添加权限校验:
import Cocoa import Quartz func checkAccessibilityPermission() -> Bool { let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] return AXIsProcessTrustedWithOptions(options) }
2. 扩展事件Tap监听点击事件
在你现有鼠标移动监控的Event Tap基础上,修改事件掩码,加入鼠标左键点击事件:
class WindowObserver { private var eventTap: CFMachPort? func setupGlobalEventMonitoring() { guard checkAccessibilityPermission() else { print("请在系统设置中开启辅助功能权限") return } let eventMask = (1 << CGEventType.mouseMoved.rawValue) | (1 << CGEventType.leftMouseDown.rawValue) let callback: CGEventTapCallBack = { proxy, type, event, refcon in guard let refcon = refcon else { return nil } let observer = Unmanaged<WindowObserver>.fromOpaque(refcon).takeUnretainedValue() switch type { case .mouseMoved: // 保留你原有的鼠标悬停逻辑 let point = CGEventGetLocation(event) observer.handleMouseHover(at: point) case .leftMouseDown: let point = CGEventGetLocation(event) observer.handleWindowClick(at: point) default: break } return event } eventTap = CGEventTapCreate( .cghidEventTap, .headInsertEventTap, .default, eventMask, callback, Unmanaged.passUnretained(self).toOpaque() ) guard let tap = eventTap else { return } let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0) CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes) CGEventTapEnable(tap, true) } // 你的原有鼠标悬停处理方法 func handleMouseHover(at point: CGPoint) { // 原有的窗口信息打印逻辑 } }
3. 点击事件处理:定位窗口并触发全屏
实现handleWindowClick方法,通过点击坐标找到目标窗口,调用全屏接口:
extension WindowObserver { func handleWindowClick(at point: CGPoint) { guard let windowInfoList = CGWindowListCopyWindowInfo(.optionOnScreenOnly, kCGNullWindowID) as? [[String: Any]] else { return } for windowInfo in windowInfoList { guard let bounds = windowInfo[kCGWindowBounds as String] as? [String: CGFloat], let windowNumber = windowInfo[kCGWindowNumber as String] as? CGWindowID, let pid = windowInfo[kCGWindowOwnerPID as String] as? pid_t else { continue } let windowRect = CGRect(x: bounds["X"]!, y: bounds["Y"]!, width: bounds["Width"]!, height: bounds["Height"]!) // 转换坐标(Mac屏幕原点在左下角,Quartz事件坐标在左上角) let flippedPoint = CGPoint(x: point.x, y: NSScreen.main!.frame.height - point.y) if windowRect.contains(flippedPoint) { // 激活目标应用 guard let app = NSRunningApplication(processIdentifier: pid) else { continue } app.activate(options: .activateIgnoringOtherApps) // 找到对应窗口并切换全屏状态 if let window = app.windows.first(where: { $0.windowNumber == Int(windowNumber) }) { window.toggleFullScreen(nil) } break } } } }
注意事项
- 权限问题:首次运行会弹出辅助功能权限请求,需在「系统设置-隐私与安全性-辅助功能」中勾选你的应用
- 窗口兼容性:部分系统级弹窗、无标题窗口可能不支持全屏,可添加额外判断逻辑跳过这类窗口
- 性能优化:全局事件监听中尽量减少重复计算,避免影响系统流畅度
内容的提问来源于stack exchange,提问作者Josué H.
相关产品推荐
相关产品推荐

