AppleScript - перебрать все открытые приложения/процессы и выполнить команду меню

Я пытаюсь написать AppleScript, который будет запускаться с помощью горячей клавиши в Keyboard Maestro на MacOS.

Что я хочу сделать, и, пожалуйста, не предлагайте НИЧЕГО ДРУГОГО, например, скрыть все или скрыть функциональность. Мне нужно свернуть все функциональные возможности открытых окон, включая анимацию.

Я уже могу скрыть все.

Итак, что я хочу сделать, это перебрать все открытые окна и вызвать пункт меню Окно -> Свернуть или если возможно, триггер минимизируется другим способом.

Вот что у меня есть, но работает не полностью, только частично:

tell application "System Events"
    set currentProcesses to name of every application process whose visible = true
end tell

repeat with tmpProcess in currentProcesses

    tell application "System Events" to tell process tmpProcess

        set frontmost to true
        ---activate

        tell menu bar item "Window" of menu bar 1
            click menu item "Minimize" of menu 1
        end tell

    end tell

    delay 1

end repeat

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


person mmm    schedule 14.03.2018    source источник


Ответы (4)


Вот мой первоначальный ответ на предложенную вами проблему, который, как было заявлено, должен работать в довольно последних (ish) версиях MacOS:

    use application "System Events"


    set _P to a reference to (every process whose class of windows contains window)
    set _W to a reference to (windows of _P whose value of attribute "AXMinimized" is false)

    set value of attribute "AXMinimized" of _W to true

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

    tell application "System Events" to set value of attribute "AXMinimized" of windows of processes to false

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

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

Вы спросили, могу ли я создать код аналогичного итеративного характера/структуры для одного из предложенных вами методов.

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

    use application "System Events"


    get the name of every application process whose class of windows contains window

    repeat with P in the result

        get (every window of process (contents of P) whose value of attribute "AXMinimized" is false)

        repeat with W in the result

            set the value of attribute "AXMinimized" of (contents of W) to true

        end repeat  

    end repeat

Так же, как и ваш скрипт, здесь явно перебираются все процессы приложения, извлеченные из фильтра (фильтр в вашем — это свойство visible для каждого process, тогда как фильтр в моем — это набор window объектов каждого process). Вы вольны меняться, если чувствуете в этом необходимость.

Однако, оказавшись внутри цикла repeat, который перебирает processes, ваш сценарий забыл сделать итерацию через каждое окно, принадлежащее каждому процессу. Вот почему вам понадобился резервный оператор, который устанавливает для свойства visible значение false, что просто скрывает процесс приложения (то, что вы явно указали в своем OP, что вы не хотели делать).

Если свойство visible не задано, единственным другим выполняемым действием будет щелчок пункта меню Minimize один раз для каждого процесса. Это приведет к сворачиванию переднего окна (то есть того, которое в данный момент находится в фокусе) этого процесса приложения, но все остальные окна, принадлежащие ему, останутся без изменений, т. е. только одно окно. для каждого приложения процесс будет сведен к минимуму. Все остальные просто скрыты переключателем видимости.

Решением этой проблемы было создание второго цикла repeat, вложенного в первый, который выполняет итерацию по всем окнам определенного процесса, полученным с помощью фильтра (который, как и прежде, я выбрал в качестве атрибута AXMinimized).

Тогда достаточно просто установить для атрибута AXMinimized для каждого окна значение true.

Как вы указали, одним из преимуществ вашего скрипта является то, что он сворачивает окна быстрее, чем мой. Из того, что я могу сказать, по какой-то причине фактическое свертывание анимации происходит быстрее при запуске с помощью меню, чем при запуске через настройку значения атрибута. Поэтому я пошел дальше и создал скрипт, который не пытается устанавливать атрибуты окон, а вместо этого использует ваш механизм щелчка по пункту меню Minimize:

    use application "System Events"


    set _P to a reference to (every application process whose visible is true)

    repeat with P in (_P as list)
        set frontmost of P to true

        set _M to (a reference to menu 1 of menu bar item "Window" of menu bar 1 of P)
        set _minimise to (a reference to menu item "Minimise" of _M)
        set _minimize to (a reference to menu item "Minimize" of _M)


        set _W to windows of P
        set n to count _W

        if n > 0 then perform action "AXRaise" of _W's front item

        repeat n times
            if (_minimize exists) and (_minimize is enabled) then
                click _minimize
            else if (_minimise exists) and (_minimise is enabled) then
                click _minimise
            end if
        end repeat
    end repeat

Этот скрипт, по сути, представляет собой переработанную версию вашего, использующую те же критерии фильтрации для своих процессов (whose visible is false) и щелкающий пункт меню Minimize (или Minimise), чтобы свернуть окна. Он содержит как внешний цикл repeat для processes, так и внутренний цикл repeat для windows.

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

Однако, вспоминая то, что вы указали в своем первоначальном брифе, вы конкретно спросили:

  • Для "глобального сворачивания действия, а не [для] прохождения через систему меню";
  • Не предлагать другие предложения, "такие как "скрыть все" или "скрыть" функции. Я ищу [a] функцию "свернуть все открытые окна";
  • Чтобы "[включить] анимацию."

Откровенно говоря, есть только одно решение, которое удовлетворяет всем этим критериям, и это исходный ответ, который я опубликовал. Другие решения, которые вы нашли, либо не работают, либо полагаются на скрытие окон приложений; последний вклад, который я предоставил выше, работает, но использует пункты меню, что не является вашим идеальным методом; а сценарий до этого, который впервые продемонстрировал вложенность двух циклов repeat для итерации через оба процесса и окна, может быть продемонстрирован с помощью индуктивных рассуждений как сценарий, идентичный моему исходному решению, которое, несмотря на не имеет явных итерационных операторов, которые вы привыкли видеть в языке программирования, действительно по-прежнему выполняет итерацию по объектам process и window за кулисами.

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

tell application "System Events" to set value of attribute "AXMinimized" of windows of processes to false
person CJK    schedule 15.03.2018
comment
Спасибо CJK, но это было не совсем надежно. Это было медленно, и я считаю, что это как-то рекурсивно повторяется. Не могли бы вы сделать это с рабочим образцом, который у меня есть? Здесь: stackoverflow.com/a/49338952/961018 Если вы добавите его в блок итерации. Я не смог изменить ваш код, чтобы он соответствовал этому. В основном я просто хочу установить для атрибута значение true, но не могу этого сделать, так как у меня есть процесс. - person mmm; 17.03.2018
comment
Можете ли вы сказать мне, в чем он не был полностью надежным? Я не сталкивался ни с какими ситуациями, когда это не сработало для меня, но если вы можете сказать мне, как воспроизвести случай, когда это не работает, это было бы очень полезно для меня. Кроме того, можете ли вы сказать мне, почему имеет значение, является ли метод итеративным или рекурсивным? Вы сказали в своем OP Было бы хорошо, если бы решение запускало какое-то глобальное действие по минимизации, а не проходило через систему меню. Это именно то, что делает этот ответ. - person CJK; 18.03.2018
comment
Тем не менее, я буду рад попытаться имитировать структуру кода, которую вы использовали, чтобы добиться того же результата, что и мое решение. Я опубликую код как обновление этого ответа. - person CJK; 18.03.2018
comment
Привет CJK, спасибо за такой длинный подробный ответ. Теперь он работает быстрее, однако он не работает должным образом, но я все равно приму ответ, так как считаю, что мы достигаем этого, и вы этого заслуживаете. Проблема с вашей версией заключается в том, что в настоящее время кажется, что окна в некоторых случаях свернуты, а это означает, что они также открываются, а не только закрываются, некоторые поднимаются, а затем закрываются. Искатель поднимается вверх, если он уже свернут. Я не хочу переключаться в свернутое, может быть, вы думали, что это было желательно? - person mmm; 20.03.2018
comment
Вы пробовали? Я использую Keyboard Maestro для запуска скрипта с помощью CTRL + H. - person mmm; 20.03.2018
comment
Я пробовал сценарии и не наблюдал описанного вами поведения. Единственный из этих сценариев, который даже может это сделать, — это тот, который щелкает пункт меню, так как есть команда AXRaise. Однако другие сценарии не могут делать то, что вы описываете, поскольку единственные команды, которые они когда-либо выдают, - это установка AXMinimized на true. Нет переключения. Серьезно, просто используйте последнюю команду, которую я вам дал: tell application "System Events" to set value of attribute "AXMinimized" of windows of processes to false - она ​​только минимизирует и делает это просто. - person CJK; 20.03.2018
comment
В противном случае мне интересно, есть ли проблема конкретно в вашей системе или у вас есть другие программы, которые каким-то образом мешают процессу. Это единственное, о чем я могу думать. Я не люблю нажимать на пункты меню, поэтому лично я бы не стал использовать этот скрипт. Но другие работают нормально, и если у вас возникли проблемы, которые я не могу физически воспроизвести, то я думаю, что вы должны исследовать это на своем конце. В заключение я думаю, что использование Keyboard Maestro — отличная идея. Я использую его, и это блестящая часть программного обеспечения. - person CJK; 20.03.2018
comment
На самом деле вы можете создать макрос Keyboard Maestro, который сворачивает все окна без использования AppleScript. Ознакомьтесь с действием Управление окном и используйте его в цикле управления, выполняющем итерации для каждого элемента в коллекции запущенных приложений. - person CJK; 20.03.2018
comment
Странно, если вы не получаете такого же поведения. Я должен упомянуть, что у меня несколько рабочих столов и один дополнительный монитор. Это свернуто только в активном приложении; imgur.com/a/igjk2 - person mmm; 20.03.2018
comment
Мой скрипт вроде работает, но не на 100% ошибка повлияет на другие окна - person mmm; 20.03.2018

Я считаю, что смог, по крайней мере, получить рабочую версию из приведенной выше.

Я думаю, что у меня были некоторые ошибки, когда минимизация меню не существовала, поэтому я добавил для этого try catch и резервный вариант, чтобы скрыть.

Этот скрипт должен работать:

tell application "System Events"
    set currentProcesses to name of every application process whose visible = true
end tell

repeat with tmpProcess in currentProcesses

    tell application "System Events" to tell process tmpProcess
        set frontmost to true

        try
            tell menu bar item "Window" of menu bar 1

                try
                    click menu item "Minimize" of menu 1
                on error
                    try
                        click menu item "Minimise" of menu 1
                    on error 
                        --- Optional, fallback
                        set visible to false
                    end try
                end try

            end tell

        on error
            --- Optional, fallback  
            set visible to false

        end try

    end tell

    delay 0.005

end repeat
person mmm    schedule 14.03.2018

Еще одно более медленное решение, найденное в Интернете:

tell application "System Events"

    repeat with appProc in (every application process whose visible is true)

        click (first button of every window of appProc whose role description is "minimize button")

    end repeat

end tell 
person mmm    schedule 14.03.2018

Еще один рабочий пример, пока лучший.

tell application "System Events"
    set currentProcesses to name of every application process whose visible = true
end tell

repeat with tmpProcess in currentProcesses

    tell application "System Events" to tell process tmpProcess
        set frontmost to true

        try
            tell menu bar item "Window" of menu bar 1

                try
                    click menu item "Minimize" of menu 1
                on error
                    try
                        click menu item "Minimise" of menu 1
                    end try
                end try

            end tell

        end try

        delay 0.1

        set visible to false

    end tell


end repeat
person mmm    schedule 17.03.2018