2008-12-07 2 views
9

Я использую API доступности, чтобы определить, когда какое-то приложение открывает окна, закрывает окна, когда окна перемещаются или изменяются, или становятся основными и/или сфокусированными. Однако клиентское приложение, похоже, перемещает окно на передний план без уведомления об API доступности, которое запускается .Как я могу использовать API доступности Cocoa для обнаружения того, что окно выведено вперед?

Как мое приложение может обнаружить, когда другое приложение приносит окно вперед, не делая его ключом?

Я в надежде найти решение, которое работает на OS X 10.4 и 10.5

Больше информации: Я использую эти заявления на данный момент. Они отлично работают, когда пользователь вручную выбирает окно для вывода на передний план. Но он не работает, когда приложение непосредственно выводит окно на передний план.

AXObserverAddNotification(observer, element, kAXMainWindowChangedNotification, 0); 
AXObserverAddNotification(observer, element, kAXFocusedWindowChangedNotification, 0); 

ответ

7

Я был не в состоянии подписаться на текущие изменения окна, но вы можете попросить доступности API для текущего приложения, а самое окно переднего плана текущих приложений.

Представьте, что вы есть класс с именем CurrentAppData, со следующими данными:

@interface CurrentAppData : NSObject { 
    NSString* _title; 
    AXUIElementRef _systemWide; 
    AXUIElementRef _app; 
    AXUIElementRef _window; 
} 

Код, чтобы найти текущее приложение выглядит примерно так:

-(void) updateCurrentApplication { 
    // get the currently active application 
    _app = (AXUIElementRef)[CurrentAppData 
          valueOfExistingAttribute:kAXFocusedApplicationAttribute 
             ofUIElement:_systemWide]; 

    // Get the window that has focus for this application 
    _window = (AXUIElementRef)[CurrentAppData 
           valueOfExistingAttribute:kAXFocusedWindowAttribute 
              ofUIElement:_app]; 

    NSString* appName = [CurrentAppData descriptionOfValue:_window 
              beingVerbose:TRUE];  

    [self setTitle:appName]; 
} 

В этом примере переменная _systemWide является инициализируется в функции init init как: _system = AXUIElementCreateSystemWide();

Функция класса valueOfExistingAttribute выглядит следующим образом:

// ------------------------------------------------------------------------------- 
// valueOfExistingAttribute:attribute:element 
// 
// Given a uiElement and its attribute, return the value of an accessibility 
// object's attribute. 
// ------------------------------------------------------------------------------- 
+ (id)valueOfExistingAttribute:(CFStringRef)attribute ofUIElement:(AXUIElementRef)element 
{ 
    id result = nil; 
    NSArray *attrNames; 

    if (AXUIElementCopyAttributeNames(element, (CFArrayRef *)&attrNames) == kAXErrorSuccess) 
    { 
     if ([attrNames indexOfObject:(NSString *)attribute] != NSNotFound 
       && 
      AXUIElementCopyAttributeValue(element, attribute, (CFTypeRef *)&result) == kAXErrorSuccess 
     ) 
     { 
      [result autorelease]; 
     } 
     [attrNames release]; 
    } 
    return result; 
} 

Предыдущая функция была взята из примера Apple, UIElementInspector, который также является отличным ресурсом для изучения о доступности API.

5

В Mac OS X приложения и окна являются совершенно разными, с приложениями, содержащими окна; они не были раньше - то же самое, что и в Microsoft Windows. Вам необходимо определить активацию и деактивацию каждого приложения.

Вы сделаете это, наблюдая за kAXApplicationActivatedNotification и kAXApplicationDeactivatedNotification. Объектом этих уведомлений является активизация и деактивация приложения. Вам также необходимо будет обнаружить запуск приложений и их выход; вы можете сделать это, используя диспетчер процессов или NSWorkspace. Оба этих API могут предоставить вам идентификатор процесса, который можно использовать для создания объекта AXApplication.

3

Взгляните на пример iChatStatusFromApplication в документации разработчика. Это именно то, что вам нужно :)