Objective c OSX:如何检测任务控制是否正在运行?

Objective c OSX:如何检测任务控制是否正在运行?,objective-c,macos,cocoa,Objective C,Macos,Cocoa,当任务控制运行时,它会阻止应用程序接收键盘和鼠标事件。它还让最后一个运行的应用程序认为它仍然有焦点。这对我来说是个问题,因为如果我在启动任务控制时按住鼠标按钮或键,我不会收到keyUp或mouseUp事件,并且我的应用程序会像按住鼠标按钮或键一样运行 我想要一种方法,可以在任务控制处于活动状态时读取键盘和鼠标事件,也可以检测任务控制处于活动状态。理想情况下,我希望能够做到后者,因为在任务控制运行时,我无法有效地使用我的应用程序 我尝试了几件运气不佳的事情: 使用AddGlobalMonitor或

当任务控制运行时,它会阻止应用程序接收键盘和鼠标事件。它还让最后一个运行的应用程序认为它仍然有焦点。这对我来说是个问题,因为如果我在启动任务控制时按住鼠标按钮或键,我不会收到keyUp或mouseUp事件,并且我的应用程序会像按住鼠标按钮或键一样运行

我想要一种方法,可以在任务控制处于活动状态时读取键盘和鼠标事件,也可以检测任务控制处于活动状态。理想情况下,我希望能够做到后者,因为在任务控制运行时,我无法有效地使用我的应用程序

我尝试了几件运气不佳的事情:

  • 使用AddGlobalMonitor或ForeventsMatchingMask注册键盘和鼠标事件的全局监视器。当我切换到另一个应用程序时,它会捕获鼠标事件(但不是键盘事件,尽管上面说的按键事件应该发送到全局监视器),但任务控制似乎不允许事件传播到全局监视器
  • 选中
    [[NSRunningApplication currentApplication]{isActive,ownsMenuBar}]
    。 显然,我的应用程序是活动的,即使它没有接收事件
  • 检查
    [NSApp keyWindow]!=无
    。 显然,我的一个窗口应该接收关键事件。他们都不是
  • 检查任务控制是否是
    [NSWorkspace runningApplications]
    返回的正在运行的应用程序之一。任务控制在运行时不显示在此列表中
  • 编辑:

    我终于解决了这个问题(尽管不是很令人满意)。对于鼠标,您可以使用
    [NSEvent pressedMouseButtons]
    查询按下按钮的状态。我只是从NSLeftMouseDown和NSLeftMouseUp事件中跟踪我认为鼠标状态应该是什么,并经常将其与
    [NSEvent pressedMouseButtons]
    进行比较,以确保它们一致。如果不是,那么我知道有什么东西劫持了我的NSLeftMouseUp事件,并相应地采取行动


    对于键盘,我找不到查询键盘状态的方法,因此无法进行类似的解决方法。我最后禁用了使用when键切换应用程序。

    可能是我遗漏了什么,但您是否尝试使用事件点击而不是全局监视?

    您是否使用NSTask在bash级别进行了尝试?类似于
    ps-faxU
    的东西应该列出所有正在运行的进程,然后您可以解析输出,或者实际上您可以使用
    ps-faxU | grep-i“任务控制”
    (在我的脑海中,我不确定如何调用该进程,但类似“任务控制”的东西似乎是合法的)。也许不是最优雅的解决方案,但如果没有其他解决方案,它可能是值得的。

    看来DTrace确实能够看到任务控制被激活。尝试运行:

    sudo fs|u用法-filesys|grep任务

    从命令行,然后从/Application文件夹启动任务控制应用程序


    您应该看到很多与任务控制启动相关的输出。不幸的是,使用键盘快捷键或滑动并没有显示相同的输出。当然,在生产代码中使用DTrace并不是我真正推荐的做法。

    至少在OS X 10.10中,您可以使用此代码检查任务控制是否处于活动状态:

    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
    }
    

    简而言之,该代码检查OSX Dock进程拥有的特定窗口是否在屏幕上可见,以及它是否位于特定位置。如果两个条件都满足,任务控制将立即激活。代码将在沙盒应用程序中工作,不需要辅助设备的权限。

    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;
    }
    
    bool Window::missionControlIsActive(){
    布尔结果=假;
    CFArrayRef windows=CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly+kCGWindowListExcludeDesktopElements,kCGNullWindowID);
    对于(int i=0;i1.0且num<1000000)继续;
    结果=真;
    打破
    }
    CFRelease(windows);
    返回结果;
    }
    
    来自文档:“只有在启用了可访问性或您的应用程序受信任可访问性访问(请参阅AXIsProcessTrusted)的情况下,才能监视与密钥相关的事件。”–这可能就是您没有获得密钥事件的原因。在系统的可访问性首选项中启用“辅助设备访问”,并查看是否有任何变化。没错,启用可访问性确实会给我全局关键事件,但在任务控制处于活动状态时不会。我建议您提交错误报告:developer.apple.com/bugreporter-另外,最好让支持者想出解决方案,而不是提出具体的要求。也就是说,缺陷报告应该只清楚、简洁地识别问题。谢谢,我已经向苹果提交了一份缺陷报告。如果我从他们那里得到一个解决方案,我会向他们汇报。另请看这个非常相关的问题:我在终端上试过了。不幸的是,任务控制是存在的