Simular atajos de teclado y pulsaciones de teclas en MacOS con AppleScript

En el sistema operativo MacOS se suele tener un buen acceso a la funcionalidad de las aplicaciones a través del teclado ya que, por norma, las aplicaciones permiten el uso de atajos de teclado.

La gestión de los atajos de teclado se realiza desde el sistema operativo por lo que es posible utilizar estos atajos de teclado para poder crear scripts de AppleScript específicos para una aplicación y crear nuestras propias personalizaciones de uso de una aplicación utilizando nuestros propios scripts de AppleScript

Esto también permite que una aplicación no compatible con AppleScript pueda ser manipulada por un script utilizando los propios elementos y controles de interfaz de la aplicación no compatible.

La aplicación System Events

La aplicación System Events es un servicio del sistema operativo que permite realizar ciertas operaciones a otras aplicaciones y programas en ejecución. System Events no tiene interfaz de usuario por lo que hay que utilizarlo a través de otra aplicación o un script de AppleScript

Con System events podemos controlar el teclado, el ratón, el volumen de nuestro Macbook y muchas cosas más. Veremos en más detalles a System Events en otros artículos.

Dentro del diccionario de System Events para AppleScript se encuentra el comando keystroke el cual nos permite simular una pulsación de teclas desde nuestro script.

El comando keystroke para ser utilizado sobre una aplicación requiere que dicha aplicación esté siendo ejecutada en ese momento. Pero si el comando es un atajo de teclado general de MacOS entonces el comando keystroke puede ser utilizado sin ningún requisito previo.

Para el comando keystroke debemos indicar qué teclas queremos pulsar pero hay que identificar entre teclas alfanuméricas y teclas modificadoras. Las teclas modificadoras son la tecla de mayúsculas, comando, control, alt, etc.

La forma de usar el comando keystroke es la siguiente:


tell application "System Events" to keystroke "letra a pulsar" using teclas modificadoras

También podemos utilizar el código numérico de la tecla en lugar de su representación literal. Su sintaxis es la siguiente:


tell application "System Events" to key code número de la tecla using teclas modificadoras

Unos ejemplos simples

En un editor de textos vamos a escribir la frase Hola mundo simulando las pulsaciones de teclado. El código es:


tell application "System Events" to keystroke "Hola mundo!"

Vamos a enviar el atajo de teclado Comando+n para abrir una nueva ventana en la aplicación que esté activa en ese momento. El código es el siguiente:


tell application "System Events" to keystroke "n" using command down

Convertir un AppleScript en una aplicación para MacOS

AppleScript permite a cualquier usuario de MacOS realizar pequeñas utilidades de forma rápida y sencilla pero el resultado sigue siendo un script que requiere de una aplicación para ser ejecutado. Pero esto no es del todo cierto

El Editor de scripts que ofrece Apple nos permite convertir un script de AppleScript en una aplicación para MacOS.

Un pequeño ejemplo para empezar

Para continuar vamos a partir de un pequeño ejemplo de script que sólo mostrará una alerta por pantalla. El código es el siguiente:


on run
display alert "Esto es un mensaje de prueba."
end run

Una vez escrito nuestro script y tras haberlo guardado con un nombre apropiado es el momento de convertirlo en aplicación.

Exportando un AppleScript como aplicación

En el menú Archivo de la barra de menú del Editor de scripts encontramos la opción de Exportar ….

Al activar la opción de Exportar … aparecerá un cuadro de diálogo para exportar nuestro script. Nos solicitará un nombre, una carpeta de destino y un formato. Ese campo formato es el que nos interesa.

Como formato podremos exportar a script, paquete de scripts, texto y aplicación. Es el formato aplicación el que nos interesa.

Dependiendo de la versión de MacOS que estemos ejecutando el campo formato también estará disponible en el cuadro de diálogo para guardar nuestro script.

Cómo reproducir un sonido en AppleScript utilizando comandos de Terminal

Con AppleScript, al igual que vimos en el artículo de Cómo reproducir un sonido al iniciar sesión en OSX podemos ejecutar comandos del terminal de forma sencilla para realizar operaciones.

En este artículo vamos a seguir con el ejemplo que seguimos con Automator y vamos a reproducir un sonido utilizando el comando de terminal afplay.

En AppleScript para ejecutar una orden en el terminal debemos utilizar la orden do shell script seguida de una cadena de texto entre dobles comillas (").

En AppleScript el ejemplo que hicimos con Automator quedaría así:


on run
do shell script "afplay /System/Library/Sounds/Blow.aiff"

A diferencia de Automator en este caso conseguimos el mismo efecto de forma más sencilla y con menos trabajo. Pero AppleScript no es siempre más sencillo de utilizar que Automator. Es más, desde Automator podemos ejecutar diversos scripts de AppleScript para realizar flujos de trabajo más complejos. Debemos decidir en cada caso qué opción es la más apropiada dependiendo qué función queremos crear.

Control de flujo de la aplicación usando estructuras condicionales en Swift

En Swift al igual que en otros lenguajes de programación la ejecución de un programa cambia según se vayan cumpliendo una serie de condiciones. Por esta razón todos los lenguajes de programación incluyen algún tipo de estructura condicional para poder controlar el flujo de ejecución de nuestro programa.

La mayoría de estructuras condicionales cumplen esta estructura:

Si se cumple una condición
entonces haz algo

Esto en Swift se consigue con la sentencia if y su sintáxis es la siguiente:


if condicionVerdadera {
// Codigo a ejecutar si se cumple la condicion
}

La condición siempre será una comparación booleana (devolverá verdadero o falso) y sólo se ejecutaría el código entre llaves si la comparación es verdadera.

Veamos un ejemplo sencillo.


/*
Playground de ejemplo de condicionales
*/
let num1 = 23
let num2 = 33

if num1 < num2 { print("Num1 es menor que num2") } if num1 > num2 {
print("Num1 es mayor que num2")
}
if num1 == num2 {
print("Num1 es igual que num2")
}

Comparaciones en Swift

La mayoría de comparaciones que se realizan en Swift son comparaciones de valores almacenados por variables u objetos. En Swift tenemos inicialmente las siguientes operaciones de comparación:

==
Igual a
!=
distinto de
<
Menor que
>
mayor que
<=
Menor o igual que
>=
mayor o igual que

Con este conjunto de comparaciones podemos resolver la mayoría de progremas de cualquier aplicación.

Ámbitos en Swift

En Swift el uso de las llaves ({ }) se utiliza para agrupar un trozo de código que pertenecerá a un mismo ámbito.

Los ámbitos no sólo se utilizan para determinar qué conjunto de órdenes pertenecen a una función, parte de código a ejecutar si se cumple una condición o qué funciones y propiedades pertenecen a una clase. Un ámbito también determina qué recursos están fuera y dentro del ámbito. Esto significa que podemos usar variables y constantes que estén por encima del ámbito pero todo aquello que declaremos dentro del ámbito no podrá ser utilizado fuera de él.

Veamos esto en un ejemplo de código.


/*
Playground de ejemplo de ambitos en Swift
*/

let numFuera = 3
do {
let numDentro = 5
print("fuera= \(numFuera) dentro = \(numDentro)")
}
print("fuera= \(numFuera) dentro = \(numDentro)")

Si intentamos ejecutar el código anterior obtendremos el siguiente error:

Playground execution failed:

error: PlayGroundTest.playground:4:38: error: use of unresolved identifier 'numDentro'
print("fuera= \(numFuera) dentro = \(numDentro)")
                                     ^~~~~~~~~

Esto se debe a que en la última línea de código, en el segundo uso de la función print() estamos haciendo referencia a la constante numDentro que está declarada dentro de un ámbito y esa función print() está siendo ejecutada fuera de ese ámbito.

Veremos más adelante más detalles de los ámbitos. Por ahora sólo nos interesa saber que las llaves nos permiten crear bloques de código agrupado y que los recursos creados y declarados dentro de un bloque son para ser utilizados dentro de ese bloque o dentro de los sub bloques que contenga.

Encadenando y anidando condicionales

Relacionada con la sentencia if tenemos la sentencia else que nos permite ejecutar un bloque de código si no se cumple la condición que estamos evaluando. Sería algo como:

Si se cumple una condición
  entonces haz algo
Si no 
  entonces haz otra cosa

Con la sintáxis de Swift el ejemplo sería el siguiente:


if condicionVerdadera {
// Codigo a ejecutar si se cumple la condicion
} else {
// Codigo a ejecutar si no se cumple la condicion
}

Un ejemplo práctico podría ser este:


/*
Playground de ejemplo de condicionales
*/
let num1 = 23
let num2 = 33

if num1 < num2 { print("Num1 es menor que num2") } else { print("Num1 no es menor que num2") }

Podemos encadenar varios else if para optimizar nuestro código. Nuestro ejemplo inicial quedaría de la siguiente forma:


/*
Playground de ejemplo de condicionales
*/
let num1 = 23
let num2 = 33

if num1 < num2 { print("Num1 es menor que num2") } else if num1 > num2 {
print("Num1 es mayor que num2")
}
else if num1 == num2 {
print("Num1 es igual que num2")
}

Además dentro de un dominio de una condición podemos incluir nuevas condiciones creando condiciones anidadas. Veamos un ejemplo práctico


/*
Playground de ejemplo de condicionales
*/
let num1 = 23
let num2 = 33

if num1 < num2 { if num1 == 23 { print("Num1 es menor que num2 y num1 tiene el valor 23") } else { print("Num1 es menor que num2") } } else { print("Num1 no es menor que num2") }

Realizando varias comparaciones a la vez

En algunas ocasiones puede que una condición consista en el resultado de varias comparaciones. Swift, al igual que otros lenguajes de programación nos permite conjuntar comparaciones para crear una condición compuesta.

Para poder crear estas uniones entre comparaciones tenemos las palabras AND y OR qe nos permiten crearr combinaciones más complejas. Pero en Swift en lugar de utilizar la palabra AND debemos usar el doble símbolo de ampersand (&&) y para la palabra OR debemos usar el doble símbolo de línea vertical (||).

Si utilizamos el AND indicamos que ambas comparaciones deben cumplirse para que la condición sea verdadera. Pero si utilizamos el OR sólo necesitamos que se cumpla una de las comparaciones para considerar que la condición se cumple.

Veamos un ejemplo de código


/*
Playground de ejemplo de condiciones compuestas
*/

let num1 = 10
let num2 = 20
var num3 = num2 / num1
var num4 = 2

if num1 < num2 && num3 == num4 { print("num1 es menor que num2 y num3 es igual que num4") } else { print("No se cumple la condición de num1 es menor que num2 y num3 es igual que num4") } // cambiamos el valor de num4 num4 = 4 if num1 < num2 && num3 == num4 { print("num1 es menor que num2 y num3 es igual que num4") } else { print("No se cumple la condición de num1 es menor que num2 y num3 es igual que num4") } // Cambiamos and por or if num1 < num2 || num3 == num4 { print("num1 es menor que num2 o num3 es igual que num4") } else { print("No se cumple la condición de num1 es menor que num2 o num3 es igual que num4") }

Al ejecutar este código obtendremos este resultado:

num1 es menor que num2 y num3 es igual que num4
No se cumple la condición de num1 es menor que num2 y num3 es igual que num4
num1 es menor que num2 o num3 es igual que num4

Conclusiones

En este artículo hemos aprendido lo siguiente:

  • Qué es un control de flujo
  • Qué es un ámbito en Swift
  • Cómo podemos comparar variables y valores
  • Cómo anidar y encadenar controles de flujo

El uso de los bloques de control de flujo son indispensables para poder crear aplicaciones que hagan algo más que mostrar valores por pantalla por lo que es muy importante dominar bien este aspecto de la programación.

Comentarios en AppleScript

La mayoría de lenguajes de programación incluyen algún mecanismo para que el programador pueda incluir anotaciones o comentarios en el código. Esto es necesario sobre todo si ese código va a crecer mucho, se va a compartir con otros programadores o se va a trabajar de nuevo en él tras cierto tiempo y tenemos que recordar qué hacía el código y por qué decidimos hacerlo así.

Ya vimos en el artículo de Hola mundo en AppleScript al detalle que AppleScript permite incluir comentarios. En este artículo lo veremos más en detalle.

En AppleScript podemos crear un comentario de una sola línea o un comentario que agrupe un conjunto de líneas consecutivas.

Para escribir un comentario de una sola línea debemos emplear el prefijo doble guión (--) delante del comentario. Todo lo que haya a la derecha de -- se ignorará por el intérprete de AppleScript.

Para escribir un bloque de comentario en AppleScript debemos encerrar el bloque de comentario con los símbolos abre paréntesis y asterisco ((*) y cierra paréntesis y asterisco (*)). Todo lo que esté entre (* y *) se ignorará por el intérprete de AppleScript.

Ejemplo de comentarios

En el siguiente ejemplo veremos los dos tipos de comentarios que podemos realizar dentro de un script de AppleScript.


(*
AppleScript de ejemplo
(CopyLeft) Tyflos Accessible Software 2018.

Este AppleScript no hace nada importante y es una excusa para enseñar cómo funcionan los comentarios en este lenguaje de scripting.

*)

on run
-- Comienzo del script
say "Hola a todos"
-- Una pequeña pausa y nos despedimos
delay 2
say "Esto no hace nada más"
-- Fin del script""
end run

Comentarios en Swift

Cuanto más conocemos Swift más complicado se vuelven nuestros Playgrounds. Es necesario ir incluyendo anotaciones o aclaraciones en nuestro código. Veamos el siguiente ejemplo.


let num1 = 54
let num2 = 235
var resultado = 0

// Almacenamos la multiplicacion de num1 y num2 en rsultado
resultado = num1 * num2
// y lo mostramos por consola
print("El resultado de \(num1) * \(num2) es \(resultado)")

El ejemplo mostrará el siguiente resultado:

El resultado de 54 * 235 es 12690

En el código anterior hemos encontrado unas líneas de código que comienzan por dos barras inclinadas (//) esto indica que todo lo que haya a la derecha de esas dos barras inclinadas es un comentario para ayudar a comprender mejor el código.

Los programadores usamos los comentarios para multitud de funciones: describir que hace o va a hacer un trozo de código, incluir un Copyright o copyleft en el código, añadir marcas o secciones en el fichero de código para marcar zonas y movernos más rápido por un fichero de código grande, etc.

Con las dos barras inclinadas (//) sólo podemos comentar una línea de código pero en Swift podemos comentar un bloque de líneas de código si las encerramos entre los símbolos /* y */. Veamos este código de ejemplo.


/*
Playground de pruebas
w≤ww.programaraciegas.net

(Copyleft) Tyflos Accessible Software 2017
*/

// Escribimos un saludo
print("Hola mundo!")

Si ejecutamos el código anterior en un Playground se ignorarán todas las líneas de comentario y sólo se ejecutará la función print().

Conclusiones

Es muy recomendable utilizar comentarios en nuestro código tanto para nosotros mismos por si visitamos nuestro código tras mucho tiempo o por si lo compartimos con otros desarrolladores.

También podemos utilizar los comentarios para desactivar o activar zonas de código que estemos probando.

Por estas y otras razones es muy necesario que tengamos el hábito de comentar nuestro código y saber utilizar las diversas formas de incluir comentarios en nuestro código.