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

== сравнивает ссылки на объекты в Java и не является исключением для объектов String.

Для сравнения фактического содержимого объектов (в том числе String) необходимо использовать equals.

Если сравнение двух объектов String с использованием == оказывается true, это связано с тем, что объекты String были интернированы, а виртуальная машина Java имеет несколько ссылки указывают на тот же экземпляр String. Не следует ожидать сравнения одного объекта String, содержащего то же содержимое, что и другой объект String, используя == для оценки как true.

13
задан Steve McLeod 12 May 2009 в 17:10
поделиться

2 ответа

Вам нужно будет использовать API специальных возможностей, которые представляют собой простой C, расположенный внутри инфраструктуры ApplicationServices. Например:

Сначала вы создаете объект приложения:

AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );

Затем вы получаете окно из этого. Вы можете запросить список окон и перечислить, или вы можете получить самое переднее окно (посмотрите в AXAttributeConstants.h все имена атрибутов, которые вы бы использовали).

AXUIElementRef frontWindow = NULL;
AXError err = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, &frontWindow );
if ( err != kAXErrorSuccess )
    // it failed -- maybe no main window (yet)

Теперь вы можете запросить уведомление через функцию обратного вызова C, когда свойство это окно меняется. Это четырехэтапный процесс:

Сначала вам понадобится функция обратного вызова для получения уведомлений:

void MyAXObserverCallback( AXObserverRef observer, AXUIElementRef element,
                           CFStringRef notificationName, void * contextData )
{
    // handle the notification appropriately
    // when using ObjC, your contextData might be an object, therefore you can do:
    SomeObject * obj = (SomeObject *) contextData;
    // now do something with obj
}

Затем вам понадобится AXObserverRef, который управляет процедурой обратного вызова. Для этого требуется тот же идентификатор процесса, который вы использовали для создания элемента 'app' выше:

AXObserverRef observer = NULL;
AXError err = AXObserverCreate( applicationProcessID, MyObserverCallback, &observer );
if ( err != kAXErrorSuccess )
    // handle the error

После получения вашего наблюдателя следующим шагом будет запрос уведомления об определенных вещах. См. Полный список в AXNotificationConstants.h, но для изменений окна вам, вероятно, понадобятся только эти два:

AXObserverAddNotification( observer, frontWindow, kAXMovedNotification, self );
AXObserverAddNotification( observer, frontWindow, kAXResizedNotification, self );

Обратите внимание, что последний параметр здесь передает предполагаемый объект «self» в качестве contextData. Это не сохраняется, поэтому важно вызвать AXObserverRemoveNotification , когда этот объект исчезнет.

Получив наблюдателя и добавив запросы на уведомление, вы теперь хотите прикрепить наблюдателя к циклу выполнения, чтобы вас можно было отправить эти уведомления асинхронно (или вообще не используются):

CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop],
                    AXObserverGetRunLoopSource(observer),
                    kCFRunLoopDefaultMode );

AXUIElementRef являются объектами в стиле CoreFoundation, поэтому вам нужно использовать CFRelease () для их аккуратного удаления. Например, для обеспечения чистоты можно использовать CFRelease (app) после получения элемента frontWindow, поскольку приложение больше не понадобится.

Примечание о сборке мусора: чтобы сохранить AXUIElementRef в качестве переменной-члена, объявите ее следующим образом:

__strong AXUIElementRef frontWindow;

Это указывает сборщику мусора отслеживать эту ссылку на него. При назначении для совместимости с GC и не-GC используйте это:

frontWindow = (AXUIElementRef) CFMakeCollectable( CFRetain(theElement) );
44
ответ дан 1 December 2019 в 17:48
поделиться

Дальнейшие исследования показали "Quartz Display Services"

Интересная функция для моих нужд - CGRegisterScreenRefreshCallback.

3
ответ дан 1 December 2019 в 17:48
поделиться