Mejorando nuestra salud gracias a AppleScript

Es conocido que la empresa Apple está incluyendo en todos sus dispositivos móviles elementos y características para mejorar la salud de sus clientes. En el Apple watch, por ejemplo, existe una característica que nos invita a levantarnos de la silla cada hora para que mejoremos nuestra salud y adoptemos hábitos saludables.

En MacOS todavía no se ha incluido ninguna de estas características pero gracias a AppleScript podemos crear nuestras propias soluciones.

Descripción de la solución

Queremos crear con AppleScript una aplicación que cada hora nos muestre un aviso para que nos levantemos de nuestro sitio durante al menos un minuto.

Con lo que hemos aprendido en artículos anteriores esto no es demasiado complicado.

Debemos aprovechar el evento idle para crear una aplicación con AppleScript que se ejecute automáticamente cada 60 segundos y compruebe la hora. Si el valor de los minutos del reloj es igual a 50 entonces mostramos nuestro aviso.

El código podría ser algo como lo siguiente:


on mostrarAviso()
display alert "Levántate durante un minuto"
end mostrarAviso

on idle
set currentDate to current date
set minutos to (currentDate's minutes)
if minutos = 50 then
mostrarAviso()
end if
return 60
end idle

Recuerda exportar el script como aplicación como se indicó en el artículo Eventos de ejecución en aplicaciones creadas con AppleScript para que el evento idle funcione de forma apropiada.

Propuestas de mejora

El script es sencillo y funciona pero se puede mejorar de muchas formas. A continuación se indican algunas posibles mejoras que puedes incluir investigando un poco con AppleScript:

  • Reproducir un sonido de campana para que el usuario no se confunda con otra notificación
  • En lugar de mostrar una alerta ejecutemos el salvapantallas de MacOS para obligar al usuario a dejar de trabajar
  • Contabilizar cuántas horas se ha mostrado el aviso para dejar de hacerlo tras 12 horas como sucede en el Apple Watch
  • Mostrar una alerta personalizada indicando cuántas horas nos quedan por levantarnos para motivar más al usuario

Todas estas propuestas se pueden realizar con lo que ya hemos ido aprendiendo en los artículos publicados sobre AppleScript e investigando un poco.

Controlar errores de ejecución en AppleScript

A la hora de diseñar y codificar nuestros scripts de AppleScript debemos tener en cuenta que se pueden producir errores y debemos controlar lo que sucede cuando aparecen estos errores.

Por defecto en AppleScript cuando sucede un error se para la ejecución del script y, a veces, se da un mensaje de error.

Veamos un ejemplo intentando verbalizar un mensaje con una voz no instalada en el sistema:


say "Hola a todos!" using "Manolo"

Al intentar ejecutar ese código obtendremos el mensaje de error No se ha encontrado la voz.. Debemos controlar esto para que nuestro script siga funcionando perfectamente.

Bloques seguros con try

AppleScript nos permite ejecutar un bloque de código de forma segura utilizando el bloque try. Permitiendo que se ejecute el código pero si aparece un error no se parará la ejecución de nuestro script.

El bloque try utiliza la siguiente sintaxis:


try
-- código a ejecutar de forma segura
end try

Volviendo a nuestro ejemplo anterior ahora podemos evitar que se de el mensaje de error utilizando el bloque try. El código quedaría así:


try
say "Hola a todos!" using "Manolo"
end try

Reaccionando a los errores

A veces nos interesa reaccionar ante la aparición de un error. Por ejemplo, si la voz Manolo no existe, aunque usemos el bloque try tendremos un problema en nuestro script ya que el mensaje nunca llegaá al usuario ya que el mensaje no se verbalizará. La solución pasa por reaccionar al error verbalizando el mensaje de todas formas con cualquier voz que esté disponible. Para ello el bloque try posee la cláusula on error que nos permite definir un sub bloque de código dentro del bloque try que se ejecutará sólo si se produce un error. Su sintaxis es la siguiente:


try
-- Código a ejecutar
on error
-- Código a ejecutar si se produce un error
end try

El código de nuestro ejemplo quedaría así:


try
say "Hola a todos!" using "Manolo"
on error
say "Hola a todos!"
end try

Creando nuestra función

El código necesario para verbalizar un mensaje con una voz en específico de forma segura es candidato a convertirse en una de nuestras funciones habituales. El código podría ser algo como lo siguiente:


on sayWithVoice(texto, nombreDeVoz)
try
say texto using nombreDeVoz
on error
say texto
end try
end sayWithVoice

Para probar nuestra función simplemente debemos llamarla de la siguiente forma:


sayWithVoice("Hola a todos, soy Mónica", "Monica")

Cómo usar la voz de VoiceOver con AppleScript para nuestros scriptss

Otra función muy útil para aquellos usuarios de VoiceOver es la de poder utilizar la voz de VoiceOver para dar mensajes.

Con esta función podremos utilizar la voz por defecto de VoiceOver para verbalizar un mensaje pero si VoiceOver no está disponible utilizará la voz del sistema.


on sayWithVoiceOver( textToSay )
try
tell application "VoiceOver"
output textToSay
end tell
on error
say textToSay
end try
end sayWithVoiceOver

Cómo saber si VoiceOver puede ser controlado con AppleScript desde un script de AppleScript

Una función muy necesaria para los scripts de AppleScript destinados a funcionar con VoiceOver, el lector de pantallas de Apple para sus productos, es saber si VoiceOver para MacOS tiene habilitada la opción de poder ser controlado por AppleScript ya que esto nos permitirá manipular el comportamiento de VoiceOver desde nuestros scripts de AppleScript.

Para ello lo que hacemos es comunicarnos con la aplicación VoiceOver y probamos a llamar a alguna de sus funciones internas.

El código de nuestra función sería el siguiente:


on isVoiceOverRunningWithAppleScript()
set isRunning to true
-- is AppleScript enabled on VoiceOver --
tell application "VoiceOver"
try
set x to bounds of vo cursor
on error
set isRunning to false
end try
end tell
return isRunning
end isVoiceOverRunningWithAppleScript

Cómo saber si se está ejecutando VoiceOver con AppleScript

Ya hemos visto cómo crear nuestras propias funciones o rutinas con AppleScript para modularizar nuestro código. Y para ayudar a crear una librería interesante de rutinas o funciones de AppleScript vamos a ir viendo en futuros artículos algunos ejemplos de funciones útiles.

Para comenzar esta serie de artículos comenzaremos por una función muy sencilla y muy útil para usuarios ciegos de MacOS.

Saber si VoiceOver se está ejecutando

Para nuestros scripts puede que necesitemos saber si se está ejecutando VoiceOver. Veamos un ejemplo muy sencillo de una función que nos devuelve true o false dependiendo si VoiceOver se está ejecutando o no.

El código es el siguiente:


on isVoiceOverRunning()
set isRunning to false
tell application "System Events"
set isRunning to (name of processes) contains "VoiceOver"
end tell
return isRunning
end isVoiceOverRunning

Lo que hace esta función es preguntar a la aplicación System Events si se está ejecutando algún programa o servicio en nuestra máquina que se llame o que contenga la cadena de texto VoiceOver. Si encuentra algún programa o servicio que cumpla esa condición actualizaría el valor de la variable isRunning a true, si no dejaría el valor inicial que es false.

Cómo crear nuestras propias funciones en AppleScript

Dentro de cualquier lenguaje de programación es necesario utilizar alguna característica del lenguaje que permita modularizar el código para que pueda ser reutilizado, sea más sencillo de leer y mantener y esté mejor estructurado dentro del fichero de código que lo contiene. En AppleScript esto se consigue utilizando funciones o subrutinas.

Una función o subrutina en un lenguaje de programación consiste en un bloque de código que puede ser ejecutado desde otras funciones o subrutinas. Es como un pequeño programa dentro de un programa más grande.

La ejecución de una función o subrutina puede ser modificada gracias a que podemos enviarle parámetros. Por ejemplo, imaginemos una función que calcula la suma de dos números cualesquiera. Los parámetros para dicha función serían esos dos números cualesquiera.

Las funciones o subrutinas pueden devolver un valor, por ejemplo el resultado de la suma de dos números.

Creación simple de una función o subrutina

Ya hemos visto la creación y uso de funciones y subrutinas con AppleScript en otros artículos pero ahora lo vamos a ver con más detalle.

Para crear una función o subrutina utilizamos el comando on seguido del nombre que queramos darle a nuestra subrutina. El nombre de toda subrutina en AppleScript debe acabar con los símbolos de abre y cierra paréntesis ( ) ya que entre estos paréntesis es donde irán, si son necesarios, los parámetros que pasaremos a la subrutina.

A continuación del nombre de la función deberemos ir a la siguiente línea para comenzar el bloque de código a ejecutar dentro de la subrutina y por último indicamos el fin de la subrutina con el comando end seguido del nombre de nuestra subrutina pero esta vez sin los paréntesis para parámetros.


on miFuncion()
say "Esta es mi función"
end miFuncion

Llamando a una función para ser ejecutada

Para ejecutar una función simplemente debemos llamarla con su nombre seguido de los parámetros que necesite encerrados entre paréntesis. Si no requiere ningún parámetro simplemente deberemos usar los paréntesis vacíos.

Veamos un ejemplo simple en el que desde el evento run de nuestro script llamamos a nuestra función saluda().


on saluda()
say "Hola a todos"
end saluda

on run
saluda()
end run

Pasando parámetros a nuestra función

Para pasar parámetros a una función simplemente debemos declararlos a la hora de definir nuestra función con el comando on colocando cada parámetro dentro de los paréntesis separados por el caracter coma (,).

Veamos un ejemplo muy simple de una función verbalizaSuma


on verbalizaSuma(num1, num2)
set resultado to num1 + num2
say resultado
end suma

Para poder ejecutar nuestra función deberemos llamarla indicando dos números como parámetros.

El ejemplo completo sería el siguiente:


on verbalizaSuma(num1, num2)
set resultado to num1 + num2
say resultado
end verbalizaSuma

on run
verbalizaSuma(32, 23)
end run

Devolviendo un resultado desde nuestra función

Uno de los objetivos más importantes de las subrutinas o funciones es la de calcular un resultado según los valores que se le hayan pasado como parámetros. Para ello la función nos tiene que devolver un resultado.

En AppleScript utilizamos el comando return para devolver un resultado. Hay que tener cuidado ya que cualquier código que esté después del comando return no se ejecutará. Veamos el siguiente ejemplo:


on resta(num1, num2)
return num1 - num2
say "Este mensaje nunca se leerá"
end resta

Reescribamos nuestro ejemplo de la suma para que en lugar de verbalizaSuma utilicemos una función más genérica la cual sólo calculará la suma de dos números. El ejemplo quedaría así:


on suma(num1, num2)
return num1 + num2
end suma

on run
say "El resultado de sumar 22 y 33 es " & suma(22, 33)
end run

Fijaos que la llamada a la función suma() se ha indicado como un valor más de la cadena de texto que se va a verbalizar. Esto se debe a que cualquier llamada a una función se resuelve antes que el código en el que se encuentra la llamada.

Modularizar es bueno

Gracias a la posibiilidad de crear nuestras propias subrutinas o funciones podemos crear nuestra propia librería de funciones para resolver tareas como por ejemplo saber si VoiceOver está en ejecución, enviar un correo electrónico con una sola línea de código, cambiar aspectos de la interfaz gráfica de forma más sencilla, etc. Estas subrutinas pueden ser almacenadas en un fichero de código a parte y sólo copiar y pegar en el fichero de script que estemos trabajando aquellas funciones que vayamos a utilizar. De esta forma nuestro código será más sencillo de leer y mantener.