如果应用程序关注macOS,如何获取? [英] How to get if an application has focus on macOS?

查看:86
本文介绍了如果应用程序关注macOS,如何获取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要收集哪个应用程序具有焦点.为此,我的方法是:列出窗口,重点关注一个窗口,最后检查哪个进程和应用程序显示了它.如果有的话:getWindowWithFocus(),那就太好了.

I have the need to gather which application has focus. For this, my approach is to: list windows, get the one with focus, and finally, check which process and application shows it. If there were some: getWindowWithFocus(), it would be fantastic.

要求:

  • 该程序是用C ++实现的,但可以在需要时与Objective-C交互.
  • 该程序将以root特权运行.
  • 列出的窗口列表必须包含所有个用户应用程序.
  • 返回的窗口允许获取属性,例如处理过程以及是否具有UI焦点.
  • 理想情况下,不使用任何第三方工具,而仅使用标准库(STL,Unix API和macOS API,最终是Qt/Boost).
  • 必须支持BigSur的HSierra.

我设法列出了所有窗口,但现在我正努力检测窗口是否具有焦点.

I managed to list all windows, but now I am struggling in detecting if a window has or not the focus.

  • 哪个API函数可用于检查窗口是否具有焦点?有样品吗?
  • 有更好的方法解决这个问题吗?

我创建了一个POC/示例,其中列出了所有窗口,包括其中的一些属性.

I created a POC/sample which list all windows, including some of it properties.

CGWindowListCopyWindowInfo

https://developer.apple.com/documentation/coregraphics/1455137-cgwindowlistcopywindowinfo?language = objc

免责声明:这是一个POC,仅用于演示,错过了适当项目所需的代码质量.例如,CFObject不会随内存泄漏而释放.

DISCLAIM: this is a POC, just for demonstration, and miss required code quality for proper projects. For example, CFObjects are not released with the consequent memory leak.

#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CGWindow.h> // CoreGraphics 
#include <iostream>

int main()
{
    CFArrayRef ref = CGWindowListCopyWindowInfo(kCGNullWindowID, 0);
    
    CFIndex nameCount = CFArrayGetCount( ref );
    
    std::cout << "NumCounts: " << nameCount << " windows" << std::endl;
    
    for( int i = 0; i < nameCount ; ++i  )
    {
        std::cerr << " -------- " << std::endl;
        CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex( ref, i );
        
        auto printKeys = [](const void* key, const void* value, void* context) 
        {
            CFShow(key);
            std::cerr << "    ";
            CFShow(value);
        };
        
        CFDictionaryApplyFunction(dict, printKeys, nullptr);

        // Process PID can be extracted with key:kCGWindowOwnerPID
        // DOES THIS WINDOW HAS FOCUS?
    }
}

推荐答案

以下是基于

Here is an example, based on this solution, wrapped in C++ (well, actually mostly C).

唯一发现的问题是,它必须在主线程中运行,这并不方便,但这是另一个主题.

The only found problem with it is, it must run in main thread, which is not convenient, but this is another topic.

main.cpp:

#include "focus_oc_wrapper.hpp"
#include <thread>
        
int main(int argc, const char * argv[])
{
    FocusDetector::AppFocus focus;
    focus.run();

    //std::thread threadListener(&FocusDetector::AppFocus::run, &focus); //Does not works
    //if (threadListener.joinable())
    //{
    //  threadListener.join();
    //}
}

focus_oc_wrapper.hpp

focus_oc_wrapper.hpp

namespace FocusDetector
{
    struct AppFocusImpl;
    struct AppFocus
    {
        AppFocusImpl* impl=nullptr;
        AppFocus() noexcept;
        ~AppFocus();
        void run();
    };
}

focus_oc_wrapper.mm

focus_oc_wrapper.mm

#include "focus_oc_wrapper.hpp"

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "focus_oc.h"

namespace FocusDetector
{

struct AppFocusImpl
{
    OCAppFocus* wrapped=nullptr;
};

AppFocus::AppFocus() noexcept: impl(new AppFocusImpl)
{
    impl->wrapped = [[OCAppFocus alloc] init];
}

AppFocus::~AppFocus()
{
    if (impl)
    {
        [impl->wrapped release];
    }
    delete impl;
}

void AppFocus::run()
{
    [NSApplication sharedApplication];
    [NSApp setDelegate:impl->wrapped];
    [NSApp run];
}

}

focus_oc.h

focus_oc.h

#import <Foundation/Foundation.h>

@interface OCAppFocus : NSObject <NSApplicationDelegate> 
{
    NSRunningApplication    *currentApp;
}
@property (retain) NSRunningApplication *currentApp;
@end

@implementation OCAppFocus 
@synthesize currentApp;

- (id)init 
{
    if ((self = [super init])) 
    {
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                      selector:@selector(activeAppDidChange:)
               name:NSWorkspaceDidActivateApplicationNotification object:nil];
    }
    return self;
}
- (void)dealloc 
{
    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    [super dealloc];
}
- (void)activeAppDidChange:(NSNotification *)notification 
{
    self.currentApp = [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];
    
    NSLog(@"App:      %@", [currentApp localizedName]);
    NSLog(@"Bundle:   %@", [currentApp bundleIdentifier]);
    NSLog(@"Exec Url: %@", [currentApp executableURL]);
    NSLog(@"PID:      %d", [currentApp processIdentifier]);
}
@end

CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version")

project("focus_detection")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreFoundation -framework AppKit")
set ( TESTCPP main.cpp focus_oc_wrapper.mm )

add_executable( ${PROJECT_NAME} ${TESTCPP} ) 

这篇关于如果应用程序关注macOS,如何获取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆