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.

Estructuras condicionales en AppleScript

En AppleScript, al igual que en otros lenguajes de programación, existen ciertas estructuras de código para controlar el flujo de ejecución de nuestro programa. Recordemos que un script es un programa con ciertas características especiales.

La estructura más simple es la sentencia que se puede resumir como una orden que indica al programador a su programa. Un ejemplo sería la línea de código con la sentencia say que hemos visto en el ejemplo de Hola mundo de esta serie de artículos.

Otro ejemplo sería la línea de asignación de un valor a una variable.

Estructuras condicionales

Hasta ahora sólo sabemos crear AppleScripts que ejecuten una sentencia detrás de otra, almacenando información y manipulándola. ¿Pero podemos controlar aún más el flujo de ejecución?

Imaginemos que un trozo de nuestro script se ejecute a partir de una hora determinada, por ejemplo, un aviso para el usuario. Lo primero que debemos hacer es obtener la hora actual. Este ejemplo nos explica cómo hacerlo:


(*
Ejemplo para obtener la hora actual
*)
on run
set fecha to current date
set hora to fecha's hours
end run

En la variable hora se almacena el valor numérico de la hora actual.

Estructura if then

Para poder ejecutar un trozo de código si se cumple una condición debemos utilizar una estructura condicional. La estructura condicional más básica, y común a muchos lenguajes de programación, es la estructura if-then. La traducción al castellano de if, then es si, entonces….

Veamos su sintaxis en AppleScript para entenderla mejor:

if condición a cumplir then
código a ejecutar
end if

En la condición a cumplir se debe indicar una comparación u operación que devuelva un valor verdadero o falso. Ejemplo de esto son operaciones comparativas del tipo A < B, A = B, Nombre = «Jonathan»

Ampliemos nuestro ejemplo anterior para dar un mensaje por voz si la hora es mayor o igual a siete. El ejemplo quedaría así:


(*
Ejemplo para dar un aviso según la hora
*)
on run
-- obtenemos la fecha
set fecha to current date
set hora to fecha's hours
-- según la hora damos el aviso
if hora >= 7 then
say "¡Despierta! Ya es tarde"
end if
end run

En este ejemplo vemos otra forma de incluir comentarios: escribiendo dos caracteres de guión consecutivos (-) indicamos que lo que hay a la derecha de esa línea es un comentario de código. Es una forma de incluir comentarios de forma rápida.

Estructura if then else

El ejemplo anterior sólo nos avisará si son las 7 o más tarde pero no hará nada si es antes de las siete. A veces nos interesa realizar operaciones distintas tanto si se cumple la condición como si se cumple lo contrario. Una forma de hacer esto sería declarar dos estructuras if then con condiciones contrarias. Un ejemplo de esto sería:


(*
Ejemplo 2 para dar un aviso según la hora
*)
on run
-- obtenemos la fecha
set fecha to current date
set hora to fecha's hours
-- según la hora damos el aviso
if hora >= 7 then
say "¡Despierta! Ya es tarde"
end if
if hora < 7 then say "Todavía es temprano. Aprovecha." end if end run

Aunque esta solución pueda considerarse válida resulta poco eficiente y complica el código. Es poco eficiente porque para hacer una acción u otra realiza dos comparaciones. El código resulta más confuso porque ambas estructuras resultan iguales salvo por un signo matemático pudiendo provocar la confusión del programador.

AppleScript, como otros lenguajes, proporciona una solución elegante para cuando queremos ejecutar un trozo de código tanto para cuando se cumple una condición como para cuando se cumple la contraria. Veamos el ejemplo con esta nueva estructura condicional mejorada:


(*
Ejemplo 3 para dar un aviso según la hora
*)
on run
-- obtenemos la fecha
set fecha to current date
set hora to fecha's hours
-- según la hora damos el aviso
if hora >= 7 then
say "¡Despierta! Ya es tarde"
else
say "Todavía es temprano. Aprovecha."
end if
end run

Como se ve en el código aparece la palabra reservada del lenguaje else. Esta partícula nos permite incluir una separación en la estructura condicional para indicar que el código a continuación se ejecutará sólo si no se cumple la condición. La sintaxis completa es:

if condición a cumplir then
código a ejecutar cuando se cumple la condición
else
código a ejecutar si no se cumple la condición
end if

Ahora podemos crear scripts más complejos que realicen operaciones según se cumplan o no ciertas condiciones.