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

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:25:16