Как определить, какой процесс запущен, какое окно в Mac OS X?
Я хотел бы знать, возможно ли определить, какой процесс отвечает за создание / управление окном в Mac OS X.
Например, когда запускается несколько экземпляров приложения, как я могу получить идентификатор процесса (PID), соответствующий одному конкретному окну? Или, если есть модальное диалоговое окно без заголовка, как я могу получить PID его владельца?
Я знаю, что в Windows это возможно с помощью инструмента Sysinternals Suite, который предоставляет способ поиска библиотеки, работающей с некоторыми данными.
Я ищу механизм, похожий на тот, который появляется в этом посте.
В этом случае, используя Sysinternals Suite (и Process Explorer), они обнаружили, какая DLL/ программа использовала веб-камеру, выполнив поиск DLL или подстроки (в данном случае, используя физическое имя устройства).
Так есть ли какой-нибудь механизм или программа, или у вас есть идеи о том, как искать что-то подобное для Mac OS X? Как я могу определить, какой процесс запустил окно?
7 ответов
Я использовал скрипт Python. Это не надежно, но для меня это очень хорошо работает.
Я не буду публиковать полный сценарий без разрешения, но вот резюме: он использует CGWindowListCopyWindowInfo
, который импортируется из Quartz
, чтобы собрать информацию об окне из системы, затем попросит пользователя переместить желаемое окно, затем снова соберет информацию об окне и покажет информацию для тех, которые изменились. Дамп информации включает в себя идентификатор процесса, как kCGWindowOwnerPID
,
Вот код:
#!/usr/bin/env python
import time
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListExcludeDesktopElements, kCGNullWindowID
from Foundation import NSSet, NSMutableSet
wl1 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
print 'Move target window'
time.sleep(5)
wl2 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
w = NSMutableSet.setWithArray_(wl1)
w.minusSet_(NSSet.setWithArray_(wl2))
print '\nList of windows that moved:'
print w
print '\n'
Сценарий печатает информацию для окна, которое изменило положение в течение 5 секунд. Итак, вывод выглядит так:
List of windows that moved:
{(
{
kCGWindowAlpha = 1;
kCGWindowBounds = {
Height = 217;
Width = 420;
X = 828;
Y = 213;
};
kCGWindowIsOnscreen = 1;
kCGWindowLayer = 8;
kCGWindowMemoryUsage = 406420;
kCGWindowName = "";
kCGWindowNumber = 77;
kCGWindowOwnerName = UserNotificationCenter;
kCGWindowOwnerPID = 481;
kCGWindowSharingState = 1;
kCGWindowStoreType = 2;
}
)}
Я сделал инструмент под названием lswin
$ python lswin.py
PID WinID x,y,w,h [Title] SubTitle
------- ----- --------------------- -------------------------------------------
169 1956 {0,-38,1280,25 } [Window Server] Backstop Menubar
169 1955 {0,-60,1280,22 } [Window Server] Menubar
169 396 {0,-38,1280,25 } [Window Server] Backstop Menubar
169 395 {0,-60,1280,22 } [Window Server] Menubar
169 6 {0,0,0,0 } [Window Server] Cursor
169 4 {0,22,1280,25 } [Window Server] Backstop Menubar
169 3 {0,0,1280,22 } [Window Server] Menubar
169 2 {0,0,1280,800 } [Window Server] Desktop
262 404 {0,-38,1280,38 } [Google Chrome]
262 393 {0,0,1280,800 } [Google Chrome]
262 380 {100,100,1,1 } [Google Chrome] Focus Proxy
... ...
Затем вы можете использовать grep, чтобы найти pid вашего окна.
Вот исходный код скрипта:
#!/usr/bin/env python
import Quartz
#wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID)
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))
#print wl
print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + ' ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + ' ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'
for v in wl:
print ( \
str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
( \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
) \
).ljust(21) + \
'}' + \
'\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
).encode('utf8')
Существует прямой удобный для пользователя собственный инструмент ОС для проверки каждого окна, который предоставляет исчерпывающую информацию в дополнение к связанному процессу, например, иерархию исходного кода: он находится в инструментах разработчика Xcode и называется
Accessibility Inspector
@kenorb Я объединил ваши 2 версии скрипта, в основном он работает как первая, показывая разницу, но форматирование идет от второй. Также, если окно не на экране - оно не печатается, иначе оно выдает слишком много мусора
import Quartz
import time
from Foundation import NSSet, NSMutableSet
def transformWindowData(data):
list1 = []
for v in data:
if not v.valueForKey_('kCGWindowIsOnscreen'):
continue
row = ( \
str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
( \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
) \
).ljust(21) + \
'}' + \
'\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
).encode('utf8')
list1.append(row)
return list1;
def printBeautifully(dataSet):
print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + ' ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + ' ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'
# print textList1
for v in dataSet:
print v;
#grab initial set
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))
#convert into readable format
textList1 = transformWindowData(wl);
#print everything we have on the screen
print 'all windows:'
printBeautifully(textList1)
print 'Move target window'
time.sleep(5)
#grab window data the second time
wl2 = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
textList2 = transformWindowData(wl2)
#check the difference
w = NSMutableSet.setWithArray_(textList1)
w.minusSet_(NSSet.setWithArray_(textList2))
#print the difference
printBeautifully(w)
Для этого вы можете использовать Automator.app:
- Start Automator (в центре внимания)
Automator.app
+ Enter) - Создайте новый рабочий процесс.
- В меню выберите Рабочий процесс > Запись (или нажмите кнопку [Запись] на панели инструментов).
- Взаимодействуйте с окном, которое вы хотите проверить, а затем нажмите кнопку ⬛️ [Стоп] на панели инструментов записи, когда закончите. (❗️ Если система выводит сообщение об отсутствии доступа специальных возможностей, предоставьте его в системных настройках)
- Перетащите записанные интересующие шаги из раздела Watch Me Do на пустую панель справа (во время перетаскивания появится кнопка с плюсом). ПОДСКАЗКА: Вы также можете выбрать все шаги и перетащить их все вместе, чтобы создать единый сценарий.
- Просмотрите сгенерированный AppleScript, чтобы получить необходимые сведения.
ПРИМЕЧАНИЕ. Этот метод можно использовать для создания кода AppleScript для поиска окон, диалогов, установки текста, нажатия кнопок и т. Д.
Вот пример видео для записи действий мыши.
Возможно, это не совсем надежно, но, вероятно, это самое простое решение, если и когда оно сработает. Никакого программного обеспечения для установки.
- Откройте «Монитор активности» на вкладке «ЦП», отсортированной по убыванию «% ЦП».
- Нажмите и удерживайте Tabили нажмите несколько раз.
- Следите за тем, какое приложение поднимается наверх списка, и запишите его PID.
Я не уверен, что этот параметр для переключения между элементами управления в разделе «Системные настройки» → «Клавиатура» → «Ярлыки» будет учитываться здесь. Я не думаю, что это произойдет, но, как бы то ни было, мой в настоящее время не проверен.
Сценарий echo on обновлен до Python3 для тех, кто в этом нуждается. Я нашел это чрезвычайно полезным. Обратите внимание, что вам необходимо установить Quartz с помощьюpip install pyobjc-framework-Quartz
заранее.
#!/usr/bin/env python
import time
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListExcludeDesktopElements, kCGNullWindowID
from Foundation import NSSet, NSMutableSet
wl1 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
print ('Move target window')
time.sleep(5)
wl2 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
w = NSMutableSet.setWithArray_(wl1)
w.minusSet_(NSSet.setWithArray_(wl2))
print ('\nList of windows that moved:')
print (w)
print ('\n')