簡體   English   中英

OSX:如何檢測 Mission Control 是否正在運行?

[英]OSX: How to detect if Mission Control is running?

當 Mission Control 運行時,它會阻止應用程序接收鍵盤和鼠標事件。 它還使最后一個運行的應用程序認為它仍然具有焦點。 這對我來說是一個問題,因為如果我在按住鼠標按鈕或鍵的情況下啟動 Mission Control,我不會收到 keyUp 或 mouseUp 事件,並且我的應用程序的行為就像按住該鼠標按鈕或鍵一樣。

我想要一種即使在任務控制處於活動狀態時也能讀取鍵盤和鼠標事件的方法,或者一種檢測任務控制處於活動狀態的方法。 理想情況下,我希望能夠執行后者,因為在任務控制運行時我實際上無法使用我的應用程序。

我嘗試了幾件事但沒有運氣:

  1. 使用 addGlobalMonitorForEventsMatchingMask 為鍵盤和鼠標事件注冊一個全局監視器。 當我切換到另一個應用程序時,這會捕獲鼠標事件(但不是鍵盤事件,盡管文檔說 keyDown 事件應該發送到全局監視器),但任務控制似乎並沒有讓事件傳播到全局監視器。
  2. 檢查[[NSRunningApplication currentApplication] {isActive, ownsMenuBar}] 顯然,即使我的應用程序沒有接收事件,它也處於活動狀態!
  3. 檢查[NSApp keyWindow] != nil 顯然,我的一個窗口應該接收關鍵事件。 他們都不是。
  4. 檢查 Mission Control 是否是[NSWorkspace runningApplications]返回的正在運行的應用程序之一。 任務控制在運行時不會顯示在此列表中。

編輯:

我終於解決了這個問題(盡管不是很令人滿意)。 對於鼠標,事實證明您可以使用[NSEvent pressedMouseButtons]查詢按下按鈕的狀態。 我只是從 NSLeftMouseDown 和 NSLeftMouseUp 事件中跟蹤我認為鼠標狀態應該是什么,並經常將其與[NSEvent pressedMouseButtons]進行比較,以確保它們是一致的。 如果不是,那么我知道有什么東西劫持了我的 NSLeftMouseUp 事件並采取了相應的行動。

對於鍵盤,我找不到查詢鍵盤狀態的方法,因此我無法執行類似的解決方法。 我最終在按下鍵時使用演示選項禁用了應用程序切換。

至少在 OS X 10.10 中,您可以使用此代碼來檢查 Mission Control 是否處於活動狀態:

func missionControlIsActive() -> Bool
{
    var result: Bool = false
    let windowInfosRef = CGWindowListCopyWindowInfo(CGWindowListOption(kCGWindowListOptionOnScreenOnly), CGWindowID(0)) // CGWindowID(0) is equal to kCGNullWindowID
    let windowList: NSArray = windowInfosRef.takeRetainedValue() // We own the returned CFArrayRef
    for entry in windowList
    {
        if (entry.objectForKey("kCGWindowOwnerName") as! String) == "Dock"
        {
            var bounds: NSDictionary = entry.objectForKey("kCGWindowBounds") as! NSDictionary
            if (bounds.objectForKey("Y") as! NSNumber) == -1
            {
                result = true
            }
        }
    }
    return result
}

簡而言之,代碼檢查 OS X Dock 進程擁有的特定窗口是否在屏幕上可見,以及它是否位於特定位置。 如果這兩個條件都滿足,任務控制將立即處於活動狀態。 代碼將在沙盒應用程序中運行,不需要輔助設備的權限。

您是否使用 NSTask 在 bash 級別上嘗試過? ps -faxU <username>這樣的東西應該列出所有正在運行的進程,然后你可以解析輸出,或者你確實可以使用ps -faxU <username> | grep -i "mission control" ps -faxU <username> | grep -i "mission control" (在我的腦海中,我不確定如何調用該過程,但諸如“任務控制”之類的東西似乎是合法的)。 也許不是最優雅的解決方案,但如果沒有其他效果,它可能是值得的。

可能我遺漏了一些東西,但是您是否嘗試過使用事件點擊而不是全局監控?

DTrace 似乎確實有能力看到 Mission Control 被激活。 嘗試運行:

須藤 fs_usage -filesys | 任務

從命令行,然后從 /Application 文件夾啟動 Mission Control 應用程序。

您應該會看到許多與 Mission Control 啟動相關的輸出。 不幸的是,使用鍵盤快捷鍵或滑動沒有出現相同的輸出。 當然,在生產代碼中使用 DTrace 並不是我真正推薦的。

C++ 和 Qt 實現適用於最新的 OS X。

bool Window::missionControlIsActive() {
    bool result = false;
    CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly+kCGWindowListExcludeDesktopElements, kCGNullWindowID);
    for (int i = 0; i < CFArrayGetCount(windows) ; i++) {
        auto cfMutableDictionaryRef_dict    = (CFMutableDictionaryRef)CFArrayGetValueAtIndex( windows, i );
        auto cfStringRef_name = (CFStringRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowName);
        if (QString::fromCFString(cfStringRef_name) != u"") continue;
        auto cfStringRef_ownerName = (CFStringRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowOwnerName);
        if (QString::fromCFString(cfStringRef_ownerName) != u"Dock") continue;
        auto cfDictRef_bounds = (CFDictionaryRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowBounds);
        auto cfNumRef_bounds_Y = (CFNumberRef)CFDictionaryGetValue(cfDictRef_bounds, QString("Y").toCFString());
        double num;
        CFNumberGetValue(cfNumRef_bounds_Y, kCFNumberFloat64Type, &num);
        if (num > 1.0 and num < 1000000) continue;
        result = true;
        break;
    }
    CFRelease(windows);
    return result;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM