Управление окнами OSX

Я пытаюсь управлять окнами внешних приложений OSX из своего приложения. мне бы хотелось в 1. Переместите окна на экран 2. изменить размер окна на экране 3. изменить текущее активное окно приложения 4. Получить текущее активное окно.

(И я хотел бы сделать это либо через ObjC/C/С++ apis).

Каковы вызовы API, которые я должен искать, учитывая, что у меня есть CGWindowID из окон, которые я хочу контролировать? То есть я ожидаю найти функции с сигнатурами чего-то вроде: MoveWindow(CGWindowID winId, int x, int y), ResizeWindow(CGWindowID winId, int width, int height), Activatewindow(CGWindowID winId), CGWindowID GetCurrentlyActivatedWindow().

Для 3 я уже использую SetFrontProcess, чтобы вывести процесс вперед, но это не позволяет мне выбрать конкретное окно процесса, если оно имеет несколько.

Ответ 1

Один из способов сделать это - действительно использовать API доступности.

Приложение, которое я разрабатываю, делает именно это, чтобы получить переднее окно, путь к документу переднего окна и многие другие атрибуты.

Я делаю это через AppleScript. Иногда это может быть неуклюжий, но, похоже, он достаточно надежный. Я использую AppScript для отправки AppleScript из моего приложения Cocoa. Он потокобезопасен и более стабилен, чем альтернативы - либо Scripting Bridge, либо NSAppleScript.

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

  • Переместить переднее окно до 100, 100

    tell application "System Events"
     set theprocess to the first process whose frontmost is true
     set thewindow to the value of attribute "AXFocusedWindow" of theprocess
        set position of thewindow to {100, 100}
    end tell
    
  • Изменить размер окна на 200, 300

    tell application "System Events"
      set theprocess to the first process whose frontmost is true
      set thewindow to the value of attribute "AXFocusedWindow" of theprocess
         set size of thewindow to {200, 300}
    end tell
    
  • Изменить текущее окно самого верхнего приложения

    tell application "System Events"
      set theprocess to the first process whose frontmost is true
      set thewindow to the value of attribute "AXFocusedWindow" of theprocess
         set size of thewindow to {200, 300}
         windows of theprocess
         -- Code to get ID of window you want to activate
         tell window 2 of theprocess -- assuming it window 2
               perform action "AXRaise"
         end tell
    end tell
    
  • Окно, которое активно

    tell application "System Events"
     set theprocess to the first process whose frontmost is true
     set thewindow to the value of attribute "AXFocusedWindow" of theprocess
    end tell
    

Там доступно приложение для AppScript под названием ASTranslate, которое превратит этот AppleScript в код Objective C, который вызывает соответствующие команды в AppScript.

Для получения дополнительной информации о том, как получить размер и границы окон (они доступны только для чтения, насколько я знаю) см. Son of Grab пример приложения.

Ответ 2

Используйте CGWindowListCopyWindowInfo для захвата kCGWindowOwnerPID для каждого окна. Затем вы можете использовать "распределенные объекты", если вы хотите получить доступ к материалам ObjectiveC, или Mach RPC для других вещей. Все это описано в http://developer.apple.com

Есть много веских причин для сообщения других приложений - например, при разработке новых пользовательских интерфейсов, которые не являются ни мышами, ни клавиатурами.

Ответ 3

Основываясь на вашем комментарии, вы можете сделать это с помощью API доступности OS X, но я считаю, что "доступ для вспомогательных устройств" должен быть включен в пользовательских настройках доступности.

Там есть стороннее shareware-приложение, чье имя ускользает от меня в тот момент, когда вы можете перемещать любое окно (и, я думаю, изменяю его размер) с помощью команд клавиатуры.

Ответ 4

Доступность должна быть включена в Системных настройках, чтобы это работало. Это applescript, но может использоваться в objective-c с помощью скриптового моста.

-- Moves safari window by deltaposition
tell application "System Events"
    tell application "Safari"
        set win to first window
        set b to bounds of win
        set deltaposition to {50, 0}
        set bounds of first window to {(item 1 of b) + (item 1 of deltaposition), (item 2 of b) + (item 2 of deltaposition), (item 3 of b) + (item 1 of deltaposition), (item 4 of b) + (item 2 of deltaposition)}
    end tell
end tell

Ответ 5

Я думаю, вы должны объяснить, почему вы хотите это сделать. Единственные утилиты, которые я знаю об этом, перемещают все окна других приложений - это Spaces и Expose, которые оба поставляются Apple. Если вы хотите взять на себя весь экран, для этого существует общедоступный API, но при перемещении окна других приложений вызывает подозрение.

Ответ 6

Я новичок здесь, поэтому это должно быть представлено как ответ, а не комментарий. Я написал приложение .NET(PlaceMint) делает именно это в Windows и не является подозрительным вообще. PlaceMint помогает организовать ваши окна структурированным способом, определенным пользователем. Все, что он делает, - это делать такие вещи, как перемещение или изменение размера окон на основе правил, определенных пользователем. Кто-то спросил меня, могу ли я сделать порт для OSX, но я так и не зашел слишком далеко, потому что не смог найти определение API, подобное тому, которое было предоставлено в Windows (переадресация DLL-вызовов на user32.dll, например SetWindowPos()).