Получение номера окна через OSX Accessibility API - PullRequest
21 голосов
/ 30 мая 2011

Я работаю над приложением, которое перемещает окна сторонних приложений по экрану.

Чтобы получить обзор всех открытых в данный момент окон, я использую

CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);

Это возвращаетмассив словарей, определяющих каждое открытое окно.Вот пример возвращаемого словаря:

{
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 442;
        Width = 475;
        X = 3123;
        Y = "-118";
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 907184;
    kCGWindowName = Untitled;
    kCGWindowNumber = 7328;
    kCGWindowOwnerName = TextEdit;
    kCGWindowOwnerPID = 20706;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
    kCGWindowWorkspace = 3;
},

Словарь полон полезной информации, используемой в другом месте, но не имеет объекта доступности, который можно было бы использовать для изменения позиций окон.Окна четко обозначены номером окна.

Сейчас я использую PID (kCGWindowOwnerPID) для создания объекта доступности для приложения окна:

AXUIElementRef app = AXUIElementCreateApplication(pid);

Затем следует получение списка всехWindows приложение открылось с помощью AXUIElementCopyAttributeValues:

NSArray *result;

AXUIElementCopyAttributeValues(
                               (AXUIElementRef) app, 
                               kAXWindowsAttribute,
                               0,
                               99999,
                               (CFArrayRef *) &result
                               );

Это работает и возвращает массив AXUIElements.Вот где я застрял.Похоже, не было вызова API для получения номера окна объекта доступности.Есть ли способ либо

a) Найти номер окна объекта доступности (чтобы в конечном итоге перебрать массив и найти правильное окно)

или

b) В противном случае ясносопоставить окно, описанное в массиве, возвращенном CGWindowListCopyWindowInfo, с объектами специальных возможностей, возвращаемых AXUIElementCopyAttributeValues?

Ответы [ 2 ]

23 голосов
/ 16 июня 2011

В итоге мы наняли специального разработчика специальных возможностей для этой задачи.

Оказывается, что это невозможно сделать без использования недокументированных API (в нашем случае это не так).

К счастью, есть практический обходной путь:

Зацикливание на всех открытых окнах приложения. Получить их должность, размер и название:

AXUIElementCopyAttributeValue(target, kAXPositionAttribute, CFTypeRef*)&posValue);
AXUIElementCopyAttributeValue(target, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
AXUIElementCopyAttributeValue(target, kAXTitleAttribute, (CFTypeRef*)&titleValue);

Затем преобразуйте позицию и размер в фактические значения CGPoint и CGSize:

AXValueGetValue(posValue, kAXValueCGPointType, &point);
AXValueGetValue(sizeValue, kAXValueCGSizeType, &size);

Сравните размер, положение и заголовок со значениями, возвращаемыми объектом в CGWindowListCopyWindowInfo(). Если они совпадают, вы можете смело предположить, что это окно, которое вы искали, и использовать уже открытый AXUIElement (target в нашем случае) для его работы.

Затраты на цикл по всем открытым окнам оказываются незначительными в OSX. Количество одновременно открытых окон ограничено.

Кроме того, хотя это не на 100% точно (возможно, что 2 окна имеют одинаковую позицию, размер и заголовок), мы не сталкивались с реальной ситуацией, когда это происходит до сих пор.

9 голосов
/ 19 августа 2013

Существует закрытая функция для получения номера окна CG для данного объекта AX для окна: _AXUIElementGetWindow.Больше деталей в обсуждении SO Уникальная идентификация активного окна в OS X Похоже, что нет никакого открытого API, чтобы выполнить задачу со 100% вероятностью.Идентификация окон по заголовку и фрейму (как описано в ответе выше) будет работать в 99,9% случаев.

...