La commande «delay» d'AppleScript ne fonctionne pas depuis le passage à Yosemite

10

Remarque: Le problème avec a delayété résolu dans OS X 10.11 El Capitan.

Depuis que je suis passé à Yosemite, les scripts Apples qui utilisent des retards ont cessé de fonctionner. Comment puis-je réparer cela?

Voici le plus simple Applescript du monde, pour un exemple simple:

set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0
delay 5
set volume output volume 20
delay 5
set volume output volume 0

Cela devrait prendre 30 secondes. Si je l'exécute dans Script Editor (anciennement Applescript Editor), cela prend 30 secondes. Mais si j'enregistre ce script en tant qu'application, lorsque je lance l'application, les retards sont ignorés et l'application prend une fraction de seconde pour se terminer.

Comment puis-je forcer Applescript à attendre un certain temps avant de passer à l'étape suivante? Est-ce un problème de Yosemite? Existe-t-il une solution de contournement fiable?

2oh1
la source
Cela fonctionne comme prévu sur mon Mac (10.10.1)
markhunte
Une idée de ce qui fait qu'il ne fonctionne pas sur le mien? Pour clarifier: cela fonctionne dans l'éditeur de script, mais si j'enregistre le script en tant qu'application et que je lance ensuite l'application, les retards sont ignorés. C'est la chose la plus étrange.
2oh1
J'ai le même problème le 10.10.3
Thomas Tempelmann
Signalé à Apple: openradar.me/21588747
Thomas Tempelmann
1
Ce problème a été corrigé dans OS X 10.11 El Capitan.
Chris Page

Réponses:

7

Remarque: Le problème avec a delayété résolu dans OS X 10.11 El Capitan.

@ 2oh1, vous avez la bonne idée de base dans votre réponse, mais voici une réponse complète et correcte:

La seule façon raisonnable de contourner ce problème consiste à invoquer un "retard" dans une boucle qui garantit que la durée souhaitée s'écoule avant de continuer. La meilleure façon de le faire est de remplacer le "délai" avec un gestionnaire personnalisé:

on delay duration
  set endTime to (current date) + duration
  repeat while (current date) is less than endTime
    tell AppleScript to delay endTime - (current date)
  end repeat
end delay

Cela vous permet de laisser le reste de votre script inchangé et vous pouvez utiliser "delay" normalement, par exemple,

delay 5
display alert "I like cake!"

[REMARQUE: Normalement, le gestionnaire personnalisé utilise la «durée du délai continue» pour appeler le «délai» intégré, mais j'ai constaté que, bien que cela fonctionne dans l'éditeur de script, il renvoie une erreur lorsqu'il est utilisé dans une applet («Can» t continuer le retard. (-1708) ”). J'ai contourné ce problème en disant directement à AppleScript de gérer la commande de délai au lieu d'utiliser "continuer" pour y arriver.]

Le problème est que delayles entrées utilisateur sont traitées pendant la pause du script, vous pouvez donc toujours cliquer sur les menus ou les fenêtres affichés par une applet, et il y a un bogue (corrigé dans 10.11) où l'entrée utilisateur fait delayattendre plus longtemps avant de reprendre l'exécution du script. . Si vous n'interagissez pas avec l'applet, delayfonctionne correctement.

Chris Page
la source
Est-ce que tout cela est un bug, ou y a-t-il une raison pour laquelle le retard fonctionne de cette façon avec Yosemite?
2oh1
C'est un bug que le retard ne retarde pas.
Chris Page
C'est si étrange. Je bricolais avec un script Apple qui utilise le retard l'autre nuit, et tout à coup, le retard fonctionnait à nouveau correctement. J'ai supposé que le bug avait été corrigé. Une heure plus tard, même si rien n'avait changé, le bug était de retour. Je suis vraiment dérouté. Cela n'a pas d'importance cependant. J'utilise une variable pour régler l'heure et le retard jusqu'à cinq minutes plus tard (par exemple), et cela fonctionne parfaitement. Donc ... problème résolu, mais cela n'explique pas pourquoi le problème existe. Intéressant, intéressant, intéressant.
2oh1
1
Parce qu'Apple a gaffé. Les logiciels Apple sont beaucoup moins fiables depuis qu'ils ont commencé à publier OS X chaque année. Je manque les versions mineures supérieures d'OS X (comme 10.6.8) où le système d'exploitation était solide. Vous n'avez tout simplement plus ce genre d'expérience.
William T Froggard
Si c'est un bug (avec lequel je suis d'accord), pourquoi cela n'est-il pas encore corrigé, je me demande. Quelqu'un ici a-t-il fait un rapport radar? Souhaitez-vous alors poster son identifiant? (ou / également poster sur openradar.me)
Thomas Tempelmann
5

Tout en luttant contre ce même problème, je suis tombé sur cette réponse à une question peu liée et j'ai décidé de l'essayer et cela semble fonctionner pour moi.

Remplacez simplement delay 5par do shell script "/bin/sleep 5"et obtenez le même résultat.

JCobb
la source
Merci d'avoir partagé! Comme je l'ai dit plus haut, je ne peux pas tester cela car, pour des raisons qui n'ont aucun sens pour moi, le retard 5 fonctionne comme il se doit pour moi en ce moment (je viens de le tester à nouveau il y a un instant). Je n'ai aucune idée pourquoi cela fonctionne parfois et échoue parfois. C'est si étrange. J'ai fini par utiliser une solution de contournement où j'obtiens l'heure actuelle et la définit comme une variable, puis je mets en pause le script jusqu'à ce que l'heure soit variable plus une minute (pour un délai d'une minute, évidemment). C'est maladroit, mais cela a fonctionné sans problème pendant des mois, alors qu'un simple retard a été intermittent. Pouah.
2oh1
J'utilise 10.10.5 et cette solution ne fonctionne pas et verrouille également le script pour la durée du sommeil
Greg
@Greg: S'il "verrouille le script" pendant la durée de sommeil, alors cela fonctionne. /bin/sleepattend la durée du sommeil et ne revient pas tant qu'elle n'est pas terminée. En revanche, la delaycommande intégrée d'AppleScript gère les événements d'entrée utilisateur pendant la pause du script. (C'est là que réside le bogue: s'il y a une saisie au clavier de l'utilisateur, delaycontinue l'exécution du script avant la fin du délai.)
Chris Page
3

Je ne dis pas que c'est la meilleure solution, mais cela semble avoir résolu mon problème. Au lieu d'utiliser un simple délai, qui est ignoré pour des raisons que je ne comprends pas, je suis passé à obtenir l'heure et à boucler jusqu'à ce qu'une nouvelle heure soit atteinte (il utilise toujours un délai, mais peu importe s'il ignore le délai depuis le script ne continue pas jusqu'à ce que le temps soit atteint).

# Pause for five minutes
set GetTheTime to current date
set NewTime to GetTheTime + (5 * minutes)
repeat while (current date) is less than NewTime
    delay 60
end repeat

Je meurs d'envie de savoir pourquoi le retard est ignoré (ou accéléré de façon spectaculaire?! ??), mais cela fait le travail, aussi maladroit soit-il.

2oh1
la source
La commande "delay" n'est pas "accélérée", elle est interrompue. Tout en retardant, il se trouve dans une boucle vérifiant s'il y a des événements d'entrée au clavier afin qu'il puisse vérifier la période de commande. Apparemment, il quitte incorrectement la boucle de retard lorsqu'une entrée utilisateur est détectée.
Chris Page
Intéressant! Je constate qu'il est ignoré (accéléré? Interrompu?) Même lorsque mon Mac est inactif, mais je ne sais pas pourquoi.
2oh1
Une fois qu'un événement d'entrée d'utilisateur est dans la file d'attente d'événements, delayil continuera d'être interrompu jusqu'à ce que quelque chose gère les événements et les supprime de la file d'attente.
Chris Page
2

J'ai trouvé une solution dans un message sur un forum allemand . Ajoutez ces lignes en haut de votre script:

use framework "Foundation"
use scripting additions
current application's NSThread's sleepForTimeInterval:1
Thomas Tempelmann
la source
J'ai du mal à tester votre réponse car, pour une raison quelconque, le retard fonctionne actuellement comme prévu sur mon Mac. Je ne sais pas pourquoi. J'utilise 10.10.3. Peut-être qu'Apple a corrigé ce bogue? Ou, c'est peut-être juste un problème intermittent qui n'affecte pas mon Mac en ce moment. Pouah. Comme je l'ai dit ci-dessus, ma solution de contournement consiste à faire en sorte qu'Applescript obtienne l'heure actuelle, puis retarde jusqu'à l'heure actuelle plus x.
2oh1
J'utilise également 10.10.3 et je vois toujours le problème. Étant donné que tout le monde ne voit pas le problème, il est probablement intermittent ou lié à un logiciel tiers ou à certains paramètres de préférence. Qui sait. BTW, votre solution de contournement a probablement l'inconvénient que l'application continue à utiliser 100% du temps processeur en attendant, tandis que le comportement de retard approprié consiste à mettre l'application en veille pendant cette durée, ce qui consomme moins d'énergie.
Thomas Tempelmann
J'utilise 10.10.5 et cette solution ne fonctionne pas.
Greg
@ThomasTempelmann: Le problème se produit lorsqu'il y a une entrée utilisateur. Si vous ne cliquez pas ou ne tapez pas pendant l'exécution du script, le bogue n'est pas déclenché.
Chris Page
Notez que cette solution provoque le gel de l'application pendant la durée du sommeil. delaytraite les entrées utilisateur pendant que le script est en pause, vous pouvez donc toujours interagir avec les menus et les fenêtres, par exemple.
Chris Page
0

carzyj a eu ce que je considère comme la meilleure réponse, mais lorsqu'il est combiné avec la méthode de Chris Page, vous obtenez:

on delay duration
  do shell script "/bin/sleep " & duration
end delay

Vous pouvez commenter "sur délai" à "délai de fin" pour revenir au délai d'origine.

Dickster
la source
J'ai également fait une modification de code similaire, avant de voir cela. J'utilise 10.10.5 et cette solution ne fonctionne pas et verrouille également le script pendant la durée du sommeil.
Greg
0

ceci est une modification de la solution @ chris-page

Cela semble être un équilibre entre la réactivité et la capture précise du retard.

on delay duration
    set endTime to (current date) + duration
    repeat while (current date) is less than endTime
        set delta to duration / 100
        if duration < 0.2 then
            set delta to 0.2
        end if
        tell AppleScript to delay delta
    end repeat
end delay

Mais au lieu de dire à Applescript de retarder pour la durée totale, nous lui disons simplement de retarder pour une période fractionnaire de la durée. si la période est inférieure à ce qu'Apple autorise (1/60 de seconde), nous allons simplement le régler sur ce delta. Que nous pouvons garder une certaine réactivité, tout en restant précis. le soupçon est que parfois le délai ne fonctionne pas, de sorte que la boucle de répétition tandis que le thread reste verrouillé, mais dans les scénarios de réussite, nous voulons que le delta de délai soit court afin que le processus puisse toujours être interrompu

Greg
la source
Le raccourcissement du délai demandé n'est pas nécessaire et ne peut que ralentir l'exécution du script et consommer plus de CPU en attendant. Ma version appelle simplement le délai jusqu'à ce que toute la durée souhaitée se soit écoulée, ce delayqui permet de retarder autant que possible avant de poursuivre l'exécution.
Chris Page
Notez que depuis que cette réponse a été publiée, j'ai mis à jour mon code pour utiliser à la delay endTime - (current date)place de delay duration, ce qui garantit que s'il delay n'est pas interrompu, il ne mettra pas le script en pause plus longtemps que l'heure initialement demandée, ce qui pourrait être ce que vous essayiez de faire. adresse avec cette réponse.
Chris Page
0

Donc, pour mettre tout cela ensemble, je crois que Chris veut dire ceci:

on delay duration
   set endTime to (current date) + duration
   repeat while (current date) is less than endTime
      tell AppleScript to delay endTime - (current date)
   end repeat
end delay
Dick.Guertin
la source