Logo Reaper y otras yerbas


Menú de secciones

AutoHotkey y los Antivirus:

cuando compilamos un script ahk en formato exe, estamos incluyendo a parte del código un intérprete del mismo. Este contiene las librerías que pueden ser usadas por el programa para interactuar con windows, como los atajos de teclado, funciones de sistema, etc.
Esto conlleva el problema de que al detectar los antivirus posibles cambios en el sistema lo reporte como falso positivo. Por lo que no depende en sí de lo que haga el script, sino que el dilema lo tiene con el intérprete del mismo. Una forma sería compartir los scripts sin compilar, para lo cual las personas que quieran utilizarlos tendrían que tener instalada una versión de AutoHotkey. Si esto no es posible y necesitamos compilarlos, solo queda el recomendar la creación de excepciones a los archivos para que los antivirus no los bloqueen o directamente o los eliminen.


Introducción:

Este espacio está pensado en quienes quieran realizar scripts sin muchas vueltas.
?Es la mejor práctica?, probablemente no. Sin embargo creo que esta herramienta es importante para salvar algunas barreras de accesibilidad, y por eso he decidido crear una guía rápida. Aquellas personas que quieran aprender programación, mi consejo es que intenten comenzar con los conceptos generales de la programación, y luego que estudien la sintaxis adecuada del lenguaje elegido. Van a ahorrarse muchos dolores de cabeza.
A medida que vayamos avanzando en las publicaciones, iré conceptualizando las cosas necesarias para la creación de scripts en este sencillo lenguaje de scripting.


Descarga e instalación de AutoHotkey:

En primer lugar vamos a descargar el instalador desde su página oficial.
Descargar el ejecutable
Y para instalarlo lo haremos de la siguiente manera:

  1. Ejecutar el instalador descargado pulsando la tecla aplicaciones, y seleccionando la opción ejecutar como administrador.
  2. Navegar con las flechas y pulsar en la opción Custom Installation.
  3. Buscar y seleccionar la opción Unicode 32-bit.
  4. Seleccionar la opción next.
  5. Pulsar en install.
  6. Seleccionar exit en los 2 diálogos siguientes.


Ya tenemos el intérprete instalado. En lo particular me gusta escribir código con notepad++ el cual tiene algunas opciones interesantes, sin embargo también lo pueden hacer con el block de notas propio de windows sin problemas.


Creando nuestro primer script:

Lo primero que haremos es crear un documento .ahk. Para ello nos situamos en alguna carpeta con el explorador de archivos. Sin tener nada seleccionado, abrimos el menú contextual con la tecla aplicaciones y buscamos el submenú nuevo, y dentro de este la opción AutoHotkey script. Le colocamos un nombre y pulsamos intro. Ahora si abrimos el menú contextual sobre este archivo recién creado, tendremos las opciones añadidas por el instalador de AHK:

Ahora vamos a escribir un poco de código, por lo que vamos a seleccionar la opción Edit Script.
Lo primero con lo que nos vamos a encontrar al editar el documento, es una serie de instrucciones predefinidas que podremos eliminar o no. Yo suelo hacer lo primero.
Al ejecutar un script el intérprete va a ir leyendo secuencialmente las instrucciones escritas en el documento. Podemos ir ejecutando fragmentos de código escritos en diferentes partes del archivo a través de subrutinas, funciones y demás. Pero la lectura se realiza de forma descendente.
El intérprete solo detiene su ejecución cuando se topa con la instrucción return, con un atajo de teclado o con el fin del documento. Toda esta primer parte del mismo, hasta donde se detiene por los elementos antes mencionados, pertenece al fragmento de ejecución automática que se activa al ejecutar el script.


Escribiendo código:

Como ya hemos dicho, la programación se basa en instrucciones a realizar. Estas no se escriben de cualquier forma, sino que tienen su sintaxis específica que es la que comprende el intérprete, por ejemplo. Si quisiéramos que nuestro script emita un sonido beep al ejecutarse, por más que escribamos haz sonar un pitido. Por favor hazme un beep, o jodér! suena de una vez! El interprete no hará ningún caso, y nos va a avisar que no reconoce ninguna instrucción en esas frases.
La sintaxis correcta para esa acción se denomina soundBeep, la cual recibe 2 parámetros; la frecuencia del sonido, y la duración en milisegundos. En el caso de este tipo de instrucciones llamados "comandos" los argumentos van separados por comas, por lo que un ejemplo podría ser:

soundBeep, 440, 150

Si guardamos los cambios y pulsamos intro sobre el script con esa instrucción, escucharemos un pitido en la frecuencia 440, con una duración de 150 milisegundos.
Una vez ejejecutada la instrucción el script se cierra automáticamente, ya que luego de leer la línea del soundBeep se topa con el final del documento.
Nota importante:
AutoHotkey es indiferente a las mayúsculas por lo que podremos escribir a nuestro antojo, sin embargo es una buena práctica utilizar los estilos Pascal case o Camel case, que permite a su vez una mejor lectura del código por los lectores de pantalla.
Con Pascal case se escriben con mayúsculas las primeras letras de los nombres compuestos por una o más palabras en funciones, variables, clases, etc Por ejemplo; "MiVariable", "MiFuncionDePrueba", "Clase". Este es el estilo más utilizado por los desarrolladores de scripts AHK. En el estilo camel case las mayúsculas se aplican a partir de la segunda palabra, por ejemplo; "miVariable", "miFuncionDePrueba", "clase".
Los espacios generalmente son ignorados, aunque en algunos casos si es necesario especificarlos. También podremos dejar líneas en blanco entre las instrucciones ya que estas sí son ignoradas por el intérprete.
Otra instrucción similar es soundPlay. Con ella podremos ejecutar un archivo de audio. Para ello tendremos que pasarle el parámetro con la ruta del archivo a reproducir, por ejemplo:

soundPlay, C:\Windows\Media\Ring10.wav

Sin embargo a esta instrucción tendremos que agregarle algo para que funcione, ya que si lo ejecutamos solo con ese código, podremos notar que no sucede nada.
El problema es que no le estamos dando tiempo al archivo para que suene, ya que el intérprete lee la instrucción, e inmediatamente pasa a la siguiente. En este caso como no hay nada más, se cierra. Para ello vamos a utilizar un comando llamado sleep, el cual realiza una pausa en la lectura del código, y solo continúa al cumplirse con el tiempo especificado en el parámetro del mismo.

soundPlay, C:\Windows\Media\Ring10.wav
sleep, 8000

Ahora si. Al ejecutar el script se lee la primer instrucción, se espera 8 segundos y se cierra.
Nota: Cuando trabajemos con archivos en AHK podremos utilizar 2 tipos de rutas, relativas y absolutas:
Las relativas refieren a la ruta del script como raíz. por ejemplo;

soundPlay, archivo.mp3

En el código anterior el intérprete buscará el archivo en la misma ruta donde se encuentra el script.

soundPlay, carpeta\archivo.mp3

En este código se buscará el archivo dentro del directorio llamado carpeta que debería encontrarse en el mismo lugar que el script.
Y el otro tipo son las rutas absolutas, como por ejemplo la que hemos utilizado en el primer ejemplo de la instrucción soundPlay. Es decir la ruta completa desde la unidad donde se encuentre el archivo a buscar.
Nota 2: En los comandos que solo reciban un parámetro, como el caso de sleep o soundPlay que son las que hemos visto hasta ahora, no es necesario separar ambas cosas con una coma. El siguiente código también es válido:

soundPlay C:\Windows\Media\Ring10.wav 
sleep 8000

Comandos versus funciones:

AutoHotkey tiene dos tipos principales de cosas que usa el scripter para crear código: comandos y funciones. Puede encontrar una lista de todos los comandos y funciones integradas en el siguiente link

Comandos:

Puede saber qué es un comando observando su sintaxis. Los comandos no usan paréntesis alrededor de los parámetros como lo hacen las funciones. Entonces, un comando se vería así:
Comando, Parámetro1, Parámetro2, Parámetro3
Al usar comandos, no puede colocar otros comandos en la misma línea que un comando anterior. Por ejemplo;
MsgBox, Hello Run, notepad.exe
Los comandos también se diferencian de la función en que utilizan "sintaxis heredada". Esto significa que necesita signos de porcentaje alrededor de una variable, como %Var%, y que el texto y los números no necesitan estar entre comillas, como This is some text. Además, no puede hacer cálculos matemáticos en los parámetros, a diferencia de las funciones.

Funciones:

Como se indicó anteriormente, las funciones son diferentes porque usan paréntesis. Una función típica se ve así:
Función(Parámetro1, Parámetro2, Parámetro3)
Las funciones tienen algunas diferencias principales:

  1. Puedes hacer matemáticas en ellos:
    SubStr(37 * 12, 1, 2)
    SubStr(A_Hour-12, 2)

  2. Las variables no necesitan estar envueltas en signos de porcentaje:
    SubStr(A_Now, 7, 2)

  3. Las funciones pueden ir dentro de las funciones:
    SubStr(A_AhkPath, InStr(A_AhkPath, "AutoHotkey"))

  4. El texto debe estar entre comillas:
    SubStr("Estoy escribiendo, ¡genial!", 16)

Una función generalmente devuelve un valor de manera diferente a como lo hace un comando. Los comandos necesitan un parámetro OutputVar , las funciones no. La forma más común de asignar el valor de una función a una variable es así:
MyVar := SubStr("Estoy escribiendo, ¡genial!", 16)
Esta no es la única forma, sino la más común. Está utilizando MyVar para almacenar el valor de retorno de la función que está a la derecha del operador (:=).


Atajos de teclado:

Una de las cosas en las cuales AutoHotkey se destaca, es en la facilidad con la que se pueden crear atajos de teclado.
En primer lugar necesitamos conocer los nombres claves que este lenguaje asigna a las teclas, para así poder utilizarlos sin problemas.
Las letras del alfabeto, así como los números alfanuméricos, las teclas de función y algunos signos de puntuación se denominan de forma literal. En cambio otras teclas tienen algún nombre particular, y las teclas de control (alt, shift, windows,, y control), están representadas por un signo. En la siguiente tabla describo algunas de ellas;

tecla Nombre clave
Alt "!"
shift "+"
control "^"
windows "#"
barra espaciadora "space"
Tabulador "tab"
escape "esc"
avance de página "pgDn"
retroceso de página "pgUp"
inicio "home"
fin "end"
retroceso "backSpace"
flecha arriba "up"
flecha abajo "down"
flecha izquierda "left"
flecha derecha "right"
intro "enter"
1, 2, 3, etc del pack numérico numpad1, numpad2, numpad3, etc

Para un listado completo, dejo el link del
Manual en línea

Atajo de teclado en un script:

Para utilizar un atajo simplemente debemos escribir él. o los nombres claves; y un doble 2 puntos. Por ejemplo:

f1::

En este ejemplo la tecla f1 dispararía el código que esté debajo de esa línea.
Para crear combinaciones podemos hacerlo de la siguiente manera;

^+t::

En esta línea el atajo que ejecutaría el código sería la combinación control, shift y la letra t.
Veámoslo en funcionamiento:


^t::
soundBeep, 440, 150
return

En este ejemplo, el atajo control y la letra t, ejecutará la instrucción que está debajo.


Comando Click:

Este comando nos permite realizar clicks de ratón en coordenadas específicas de la pantalla.
Al respecto de esto, existen 3 tipos de coordenadas que podremos utilizar;

Generalmente las coordenadas mas utilizadas son las relativas (window), aunque según la circunstancia, puede funcionarnos mejor alguna de las otras 2.
Para conocer la coordenada de un punto específico de la pantalla lo podemos hacer mediante el WindowSpy, que nos brinda muchos datos importantes de la ventana enfocada. El mismo lo podemos encontrar en la carpeta de instalación de AutoHotkey, o abriendo el menú contextual sobre algún script activo en la bandeja de sistemas. La manera mas cómoda de capturar estas coordenadas es a través de un script como el que comparto en el siguiente
link

En el mismo está especificado que con control, shift, c. Se copien las coordenadas relativas, especificadas en la pimera línea por CoordMode, en el portaPapeles.
Si quisieran utilizar las coordenadas client, o las Screen, simplemente editan el documento, reemplazando la palabra Window, por alguna de estas 2.
El comando click, al igual que muchos otros en este lenguaje, se puede escribir de varias maneras. Sin embargo creo que es mas claro en un comienzo utilizarlo como en el siguiente ejemplo;


CoordMode, Mouse, Window


#!p::
click, left, 350, 45, 2
return

En este ejemplo indicamos a través de la pimera línea, el tipo de coordenada que vamos a utilizar.
En la segunda, el atajo de teclado que va a realizar la siguiente acción.
En el comando click, el primer parámetro, Left, indica con que botón del mouse haremos la acción. Si quisiéramos realizar un click derecho, deberíamos escribir Right.
El parámetro siguiente es la coordenada x. El siguiente, la coordenada y. Y por último, la cantidad de clicks que se van a realizar. Si va a ser solo uno, podemos dejar ese parámetro en blanco. En ese caso, quedaría así;

click, left, 350, 45

Asimismo, podríamos utilizar este comando para solamente mover el mouse a un lugar específico, pero sin realizar un click. Para ello como último parámetro debemos escribir 0.

Click, Left, 123, 456, 0

Para realizar un click en la posición actual del mouse, simplemente escribimos click;

^j::
click
return

El comando #IfWinActive:

El mismo sirve para que los atajos de teclado solo funcionen en una ventana específica y no sea activado por error en alguna otra, produciendo algún comportamiento inesperado.
Para poder utilizarlo correctamente debemos saber en principio el nombre o clase que le asigna windows a esa ventana. Al igual que con las coordenadas podríamos utilizar el WindowSpy, pero para facilitar mas la cosa les paso un script con el cual podrán capturar nombre y clase con atajos de teclado.

Descargar el script en .ahk

Con el script abierto. al pulsar windows c copiaremos al portapapeles el nombre de la clase de esa ventana, y con windows t El título


Ejemplos:

#If WinActive("AHK_Class Notepad")
Home::
Send {Volume_Up}
Return


End::
Send {Volume_Down}
Return


En este ejemplo al pulsar la tecla inicio subirá el volúmen general de windows, y con fin, descenderá. Sin embargo solo funcionará cuando estemos situados sobre una ventana abierta del block de notas. En cualquier otra ventana las teclas cumplirán su función normal. Podríamos también usar el título de la ventana en lugar de su clase, por lo que reemplazaríamos

"AHK_Class Notepad"

por

"Sin título: Bloc de notas"


Si quisiéramos que otro atajo, por ejemplo el de cerrar el script funcione en cualquier ventana tendremos que agregar antes del atajo el comando #If.


Ejemplo completo:

#IfWinActive AHK_Class Notepad
Home::
Send {Volume_Up}
Return


End::
Send {Volume_Down}
Return


#If
#q::
ExitApp

Crear script con Pulover's Macro Creator:

Este programa está pensado para facilitar la creación de scripts a través de una interfaz gráfica. En el siguiente tutorial veremos las funciones básicas para crear un script. Pero antes, comparto una versión portable ya configurada.

Descargar macro creator portable


audio:


Crear disparador de efectos:

Una GUI ("interfaz gráfica de usuario), es una herramienta muy potente con una gran variedad de opciones. En esta ocación la utilizaremos para crear una pequeña ventana desde la cual podremos reproducir archivos.

Una gui puede estar compuesta de muchos elementos como texto, casillas de verificación, cuadros combinados, y una larga lista más. Sin embargo, hoy utilizaremos con botones que disparen sonidos. Lo haremos de la siguiente manera, solo pondré 3 elementos, y luego explicaré que son:
Lo primero que debemos hacer es crear la lista de elementos que serán en este caso, los disparadores de los sonidos.
Esta lista de elementos tiene que estar en la parte automática del script, es decir, que no debe haber ningún atajo o comando return antes de la misma.

Gui, Add, Button, gEtiqueta1, risa
Gui, Add, Button, gEtiqueta2, Bomba
Gui, Add, Button, gEtiqueta3, Lluvia


En estas 3 líneas tenemos lo siguiente. El nombre del comando, en este caso, Gui.
El primer parámetro, que indica que vamos a añadir algo a esa Gui. Add.
El tercer parámetro, que indica que es lo que añadiremos, en este caso, button.
el cuarto parámetro es el nombre de la etiqueta, que es hacia donde va a dirigirse el intérprete cuando pulsemos en ese botón. Se utiliza escribiendo primero una letra g, y luego un nombre para la misma.
Y por último, el nombre del botón que va a aparecer en la ventana.


Hasta aqui ya tendríamos la ventana creada, sin embargo la misma no se visualizaría al abrir el script ya que tendremos que agregar un comando más con el parámetro mostrar. Sería así.

Gui, Show,, Efectos de sonido


En este comando, el segudno parámetro nos indica que esa ventana debe ser mostrada. El tercero está vacío ya que ahí van las indicaciones de posicionamiento en la pantalla, cosa irreelevante por ahora. Y por último, el nombre que va a recibir esa ventana.
Nota: No siempre se pueden dejar parámetros en blanco en un comando, sin embargo cuando se está habilitado para hacerlo simplemente escribimos 2 comas juntas y seguimos con el resto.
Ya tenemos nuestra Gui creada, y visualizada. Ahora debemos indicar hacia donde irán esas etiquetas de cada botón al ser pulsados.
Una etiqueta cumple la misma función que un atajo de teclado, con la diferencia que la misma debe ser llamada desde algún lado. Se utiliza colocando su nombre y luego un signo de 2 puntos. Debajo escribiremos el, o los comandos, y por último un Return, para finalizar su acción.
De esta forma, nuestro script quedaría así:

Gui, Add, Button, gEtiqueta1, risa
Gui, Add, Button, gEtiqueta2, Bomba
Gui, Add, Button, gEtiqueta3, Lluvia
Gui, Show,, Efectos de sonido
Return


Etiqueta1:
SoundPlay Risa.mp3
Return


Etiqueta2:
SoundPlay Bomba.mp3
Return


Etiqueta3:
SoundPlay Lluvia.mp3
Return


^q::
ExitApp


En el caso de este script, los archivos que va a disparar deben estar en la misma ruta de la carpeta. Por defecto, se toma la raíz de la misma como ruta inicial. Y lógicamente los nombres de los archivos que usemos en el SoundPlay, debe coincidir con los que estén en ella.
Si nosotros tenemos el archivo AHK o exe en una carpeta llamada efectos, en este caso, los archivos deberán estar en la misma carpeta sueltos junto al script.
Sin embargo, si quisiéramos tener un subdirectorio con los audios tendríamos que hacer lo siguiente.
Dentro de la carpeta efectos, es decir la carpeta raíz, creamos un nuevo directorio llamado Sonidos.
Por lo que en el comando soundPlay escribimos la ruta de la siguiente forma;

SoundPlay Sonidos\Risa.mp3
SoundPlay Sonidos\Bomba.mp3
Etcétera.


Si el archivo se encuentra en una carpeta fuera de la raíz, deberemos escribir la ruta completa del mismo. Por ejemplo:

SoundPlay c:\Users\Administrador\Music\Lluvia.mp3


Si vamos a utilizar audios un poco extensos y necesitamos poder cortarlos en algún momento, la única forma de hacerlo es creando un botón que lleve a un soundPlay silencioso o inexistente, ya que el mismo no permite reproducir 2 cosas a la vez. Por ejemplo;

Etiqueta5:
SoundPlay Silencio.mp3
Return


Pueden agregar todos los audios que quieran siempre y cuando creen el comando gui coorespondiente, y su etiqueta asociada al SoundPlay.


Hacer hablar a nuestro script:

Una de las cosas importantes en la programación de scripts, es el poder interactuar con algún lector de pantallas o voz del sistema. Trabajar con Windows Sapi es bastante sencillo, por lo que comenzaremos por ahí.
La interacción con sapi se realiza a través del uso de los métodos de un objeto com. Lo primero que debemos hacer, es agregar el siguiente código a nuestro script.

Sapi := ComObjCreate("SAPI.SpVoice")
Sapi.Rate := 7
Sapi.Volume :=85


En la primer línea pasamos el objeto com a la variable Sapi.
En la segunda, especificamos la velocidad del sintetizador con el método Rate.
En la tercera, el porcentaje del volúmen con el método volume.
En estos 2 últimos podemos modificar su valor, simplemente editando el número.
Solo nos queda llamar al método Speak, que es donde hemos de especificar el texto a verbalizar como único parámetro. El mismo puede ser agregado las veces que sea necesario.

Sapi.Speak("Hola. Oigan mi preciosa voz.")


Como se habrán dado cuenta, todo lo que se quiera verbalizar debe ir entre las comillas de la función Sapi.Speak.
Otra cosa interesante es la posibilidad de verbalizar el texto que tengamos en el portapapeles. Recordemos que el mismo es una variable integrada, que la podemos utilizar simplemente escribiendo Clipboard. Para verbalizar el contenido de una variable, la misma debe ir entre los paréntesis, sin las comillas, y sin los signos de Porciento.

Sapi.Speak(Clipboard)


Un ejemplo insensato sobre el uso de la función Speak:

Sapi := ComObjCreate("SAPI.SpVoice")
Sapi.Rate := 7
Sapi.Volume :=85
Sapi.Speak("Script iniciado")
Return


#n::
Sapi.Speak("Abriendo el block de notas...")
Run Notepad
Return


#q::
Sapi.Speak("Cerrando el script...")
Sleep 2000
ExitApp


Al iniciar el script se verbalizará la primer función Speak, ya que la misma está en la parte automática del mismo.
el atajo windows n primero hará que hable el TTS, y luego abrirá el block de notas.
En el último comando, he colocado un sleep de 2 segundos para que el TTS tenga tiempo de despedirse antes del cierre del script.
Se pueden configurar unas cuantas cosas utilizando TTS, como la voz a utilizar, o crear funciones para realizar variadas acciones. Para los que tengan ganas de aventurarse un poco más en este asunto, los invito a buscar en el foro AHK. Por ejemplo.
Aquí

Descargar el ejemplo


Mensajes a través de NVDA:

En la publicación anterior hemos visto como programar mensajes utilizando Microsoft Sapi.
Sin embargo también es posible hacerlo interactuando con NVDA. Para ello vamos a utilizar una función que llama a una DLL. 2 conceptos que aún no hemos explorado, pero que podemos manejar siguiendo los pasos a continuación.
Lo primero que necesitamos son los archivos dll a los cuales llamará la función que utilizaremos.

Descargar los archivos


Las funciones son uno de los elementos mas importantes de la programación, y un poco complejo de explicar en pocas líneas. Por lo que en esta ocasión solo vamos a hacer uso de ella, y más adelante intentaremos explicarlas, y trabajarlas más en profundidad.
En algún lugar del script, debemos copiar el siguiente código:


Nvda(text)
{
return DllCall("nvdaControllerClient" A_PtrSize*8 ".dll\nvdaController_speakText", "wstr", text)
}


La primer línea tiene el nombre de la función, la cual es "Nvda", sin comillas.
Entre paréntesis el parámetro que vamos a pasarle a esta función, que en este caso será texto.
Luego entre signos de llave, está la llamada a la DLL que hemos descargado.
En esta línea es importante colocar correctamente la ruta del controlador dll. De la forma en que está creada la función, nuestros nvdaKontrollerClient deben estar en la raíz de la carpeta que contendrá el script.
Si en lugar de eso, queremos crear un subdirectorio donde copiar estos archivos,
es necesario agregar la ruta. Por ejemplo;
supongamos que en la carpeta principal donde se encontrará el ejecutable del script, creamos una carpeta llamada "Archivos", y que ahí dentro tendremos los archivos DLL. La línea quedaría así:


return DllCall("Archivos\nvdaControllerClient" A_PtrSize*8 ".dll\nvdaController_speakText", "wstr", text)


Una vez copiada la función en nuestro script, y guardado los archivos DLL en su sitio, solo nos queda llamar a la función, con el parámetro texto. Lo haremos de la siguiente forma:


f4::
Nvda("Hola mundo. ah, no, tendría que aprender otra frase. Siempre digo lo mismo...")
Return


Lo que hemos hecho en la segunda línea, es colocar el nombre de la función. En este caso, "Nvda".
Las funciones requieren que los parámetros estén entre signos de paréntesis. Y como lo que vamos a indicar es texto, también debe ir entre comillas.
Para que el NVDA lea el contenido del portapapeles, si es que hay algún texto en él, colocamos la variable Clipboard, de esta forma:


Nvda(Clipboard)


Como aclaraba en los primeros artículos de esta sección, es importante el seleccionar la distribución de 32 bits durante el proceso de instalación del AutoHotkey. Esto puede evitarnos varios dolores de cabeza con respecto a la compatibilidad, así como al uso de los controladores de NVDA. en el caso de que la ruta de la llamada al controlador sea la correcta, y aún no funcione. Pueden probar colocando el número 32 al nombre del archivo dll. Quedaría así:


return DllCall("nvdaControllerClient32" A_PtrSize*8 ".dll\nvdaController_speakText", "wstr", text)

Dejo el link del proyecto en GitHub, y el script de ejemplo:

Ver el proyecto en GitHub Descargar el archivo


Función para agregar la verbalización de NVDA o Jaws a nuestros scripts:

Les comparto este pequeño script ahk el cual solo contiene una función. En ella verifico si el proceso de JAWS está activo. EEn caso afirmativo, utilizo un objeto com con la api de JAWS y utilizo un método de la misma. En caso contrario, se llama a la dll del NVDA para que verbalice.


Uso:

Lo podremos utilizar de 2 maneras. Copiando el contenido del archivo Speak.ahk en nuestro script, o creando un include, que viene a ser lo mismo. La diferencia es que en el segundo caso, el archivo Speak.ahk debe quedar en el script al menos hasta que este sea compilado. En el caso de tener el archivo en la carpeta de trabajo de nuestro script, donde está el script en si mismo, pondríamos lo siguiente.

#Include Speak.ahk

Si lo colocamos dentro de una subcarpeta llamada "Ejemplo", sería así:

#Include Ejemplo/Speak.ahk

Y para utilizarlo dentro del código basta con llamar a la función Speak(), pasándole entre paréntesis y comillas el texto a verbalizar.

Speak("Ser o no ser. Jaws o NVDA...")

Y en el caso de verbalizar una variable, como siempre, sin comillas.

Speak(Clipboard)

Atención con la ruta de la dll del nvda. En esta función la misma está dentro de una carpeta llamada Speech. Por lo que tendrían que crear la misma en su script, y pegar el archivo de nvdaControllerClient allí dentro. En el caso de querer usar otra carpeta, modificar la línea 9, colocando el nombre de la misma en el lugar de Speech.

Descargar la función Speak


Crear menú en AutoHotkey:

La creación de menús en un script nos ayudan a a simplificar el uso del mismo. Nos permite incorporar varias acciones que de otra forma, tendrían que ser ejecutadas a través de una importante cantidad de atajos de teclado, volviendo un poco complejo su uso.
En esta entrada solo voy a explicar la creación de un menú simple, sin opciones anidadas, para que sea lo menos confuso posible. ¡Comencemos!


Ítems del menú:

Al igual que con las gui, la lista de opciones deben estar escritas en la zona automática del script, es decir que no haya ningún atajo o return antes de ellos. Lo primero que haremos será añadir los ítems que contendrá, y en cada uno tendremos que incorporar 4 parámetros que son:


En el nombre, podemos elegir cualquiera. Como subcomando utilizaremos add, ya que añadiremos un ítem al menú. En el parámetro del nombre del ítem, deberíamos colocar un nombre que identifique la acción que va a realizar, ya que será el nombre que va a aparecer en la visualización del mismo. Y por último, una etiqueta, o atajo de teclado que llamará a una acción determinada. Vamos con un ejemplo para que sea mas comprensible la explicación.

Menu, MenuName, Add, Abrir el block de notas, Notepad
Menu, MenuName, Add, Reproducir un sonido de Windows, Sound
Menu, MenuName, Add, Hacer click, Click


Menu, MenuName, Show
Return

La penúltima línea, al igual que en las gui, contiene el parámetro Show con el cual realizaremos la visualización del menú. También podríamos añadirle un atajo, para poder desplegarlo las veces que sea necesario, por ejemplo:

^m::
Menu, MenuName, Show
Return


Hasta aquí tendríamos el menú correctamente creado. Sin embargo, al pulsar sobre alguno de sus ítems no se realizaría ninguna acción ya que sus etiquetas no conducen a ningún comando.
Otra vez, al igual que con las gui, debemos programar en alguna parte del script las etiquetas y sus acciones correspondientes.


Ejemplo Completo:

Menu, MenuName, Add, Abrir el block de notas, Notepad
Menu, MenuName, Add, Reproducir un sonido de Windows, Sound
Menu, MenuName, Add, Hacer click, Click


^m::
Menu, MenuName, Show
Return


Notepad:
Run Notepad
Return


Sound:
SoundPlay C:\Windows\Media\Ring10.wav
Return


Click:
Click, Left, 1615, 20
return


En este script, al pulsar control m se va a desplegar un menú contextual que contendrá 3 ítems. Al pulsar sobre alguno de ellos se realizará la acción programada. Lógicamente la opción click no va a realizar algo concreto, simplemente hará un click inofensivo en lo que cada uno tenga en esas coordenadas de la pantalla. Lo he colocado a modo de ejemplo.

Descargar el código fuente


Subrutinas y funciones en AutoHotkey:

en cualquier lenguaje de programación, se pueden definir como un fragmento de código independiente que se ejecuta cuando se los llama y, cuando terminan, vuelven al punto del que fué llamado.
Son fundamentales para tener un código organizado, ya que evitamos repetir muchas veces las mismas acciones. También facilita su mantenimiento, porque al realizar algún cambio, lo haremos sobre ellas y no en las tantas acciones repetidas en el script.


Subrutinas:

La subrutina se ejecuta con el comando Gosub, y el nombre de la etiqueta.
Al ejecutarse realizará la acción de esa etiqueta, y al encontrar un return, continuará con la línea siguiente después de la llamada.

f1::
Gosub Sonido
Run Notepad
Return


Sonido:
SoundBeep,440,50
Return


En este ejemplo primero debería sonar un beep y luego abrirse el block de notas. Esto sucede porque la primer línea después del atajo es un gosub, el cual llevará al intérprete a la línea 6. Continuará su ejecución con la línea 7 donde se encuentra la instrucción Beep. Al encontrar un Return en la línea siguiente saltará al mismo lugar desde donde fué llamado continuando su ejecución en la línea 3, es decir, El comando Run.


Un ejemplo un poquito más complejo, aunque no verdaderamente muy práctico.

f1::
Gosub, Verificación
SendRaw NvdaSpeak(text)`n{`nreturn DllCall("nvdaControllerClient" A_PtrSize*8 ".dll\nvdaController_speakText", "wstr", text)`n}
Return


f2::
Gosub, Verificación
SendRaw NvdaSpeak("")
Send {Left 2}
Return


Verificación:
If WinActive("ahk_class Notepad")
Return
Else
{
MsgBox,0,,
(
Error.
Este atajo solo puede ser ejecutado en alguna ventana del block de notas.
)
}


Tanto el atajo f1 como f2, antes de ejecutar el SendRaw, envía a la etiqueta Verificación.
En esa etiqueta se encuentra un condicional if. Este comprueba si está activa la ventana cuyo nombre está entre paréntesis y comillas. Si está, realizará la acción que está inmediatamente debajo. Y al encontrar un Return, que es en realidad lo único que hay, vuelve al punto de la subrutina, y continúa su ejecución.
A través de else, indicamos que si no se cumple con la sentencia if, haremos lo que está debajo.
En este caso, un mensaje MsgBox. Aquí he hecho una pequeña trampa. Si luego del cerrar llave hubiese colocado un Return, luego de aceptar la ventana de MsgBox hubiese vuelto al gosub y continuaría la ejecución normalmente. Al dejarlo como último elemento del script, la subrutina se rompe, y no regresa.
Otra forma de romper una subrutina es a través de un Reload. Que reinicia el script,, por lo que tampoco continuaría la ejecución del mismo.


El comando SendRaw sirve para enviar texto literal, mas conveniente en estos casos por estar pasando signos que cumplirían otra función en un simple Send. El comando send de la línea 9 hace que la flecha izquierda, "Left", se ejecute 2 veces, "2". Para conocer las posibilidades del comando Send, pueden visitar la Publicación oficial

Descargar el ejemplo de subrutina


Funciones:

Siguiendo la línea de esta sección, que es no profundizar tanto en la sintácsis para no abrumar y dinamitar las ganas de aprender, vamos a trabajar en un uso práctico. Las funciones son realmente muy potentes y intentar abarcar todas sus posibilidades convertirían esta entrada en un testamento.


Las funciones usan el mismo concepto de la subrutina, aunque al poder recibir parámetros y enviar resultados sus posibilidades son considerablemente mayores.
Para crear una función primero debemos colocarle un nombre. Inmediatamente después, entre paréntesis, los parámetros que van a utilizarse. Por último, entre llaves, la, o las acciones a realizarse.


Un uso bastante común que suelo darle, y será el que voy a mostrar, es el de hacer click en algún lugar y que el NVDA verbalice algo referido a ese click.
Para este caso voy a usar 3 parámetros. La coordenada x, la coordenada Y, y el texto a verbalizar. Así que colocamos el nombre, y entre paréntesis separados por comas los parámetros a usar;
FunctionExample(xCoord,yCoord,Text)
Los parámetros en este caso, son variables, por lo que podemos elegir otro nombre si quisiéramos. Lo importante es el órden, ya que en la llamada a la función debemos respetar esta misma posición de parámetros que irán entre paréntesis.
Supongamos que necesitamos hacer click en las coordenadas 28, 53. Y que el NVDA pronuncie,
Abrir navegación. Para ello debemos escribir el siguiente código:

^+a::
FunctionExample(28,53,"Abrir navegación")
Return


Aquí hemos colocado el nombre de la función que hemos llamado. El primer parámetro entre paréntesis es la coordenada x, el segundo, la coordenada y. Y el último, que siempre debe ir entre comillas cuando sea un texto literal, lo que va a verbalizar el NVDA cuando ejecutemos esta acción.
Ahora armemos la función:

FunctionExample(xCoord,yCoord,text) {
Click, %xCoord%, %yCoord%
return DllCall("nvdaControllerClient" A_PtrSize*8 ".dll\nvdaController_speakText", "wstr", text)
}


Cuando ejecutemos el atajo Control Shift a, El intérprete encontrará la llamada a una función. Tomará los parámetros que hay entre los paréntesis y se moverá a la función con ese nombre. Una vez en la función, comenzará a ejecutar las acciones línea a línea. En este caso, primero hay un comando click. como podrán observar, el primer parámetro del comando click que sería la cordenada x, tiene la llamada a una variable. Esto lo podemos saber porque está entre signos de porciento. Sucede lo mismo con el siguiente parámetro. Llamada a otra variable. Estas están definidas en el llamado a la función.
Una vez realizado el click, pasa a la línea siguiente. He colocado una espera, "Sleep", para que la verbalización no quede atrapada entre otras cosas que va a decir el NVDA.
Y finalmente toda la línea de una DLLCall que nunca recordaré de memoria. En este caso simplemente copien el texto y péguenlo en el lugar correspondiente. Esta línea toma el tercer parámetro de el llamado a la función que habíamos colocado entre comillas, y hará que el NVDA verbalice ese texto, siempre y cuando el archivo DLL esté colocado en el lugar correspondiente.
Todo esto tiene sentido si vámos a repetir la función más de una vez, caso en el cual simplemente podemos escribir el llamado a la función, colocar los parámetros correspondientes y listo. Inclusive, podríamos colocar las llamadas en una sola línea junto con el atajo., por ejemplo:

^+a::FunctionExample(28,53,"Abrir navegación")


Cuando el código se escribe en una sola línea, no es necesario colocar un Return al final.
El ejemplo que pondré para descargar es sobre algunos botones del block de notas.


Puede que suene un poco a chino todo esto, pero practicando se llega a buen puerto. Un buen artículo donde está explicado este tema y donde hay mas información es en la página de Gonduana. El siguiente link tiene el artículo sobre el tema. Subrutinas y funcionas en AutoHotkey


Descargar el ejemplo de función


Crear buscador con AutoHotkey:

En este audio incorporaremos un nuevo concepto, las variables. Con ellas podemos crear un buscador para obtener rápidamente resultados de cualquier página que cuente con un formulario de búsqueda.
Para el que quiera descargar el código fuente del script, puede hacerlo desde
aquí


Audio


Crear un juego con AutoHotkey:

En este audio seguiremos repasando conceptos importantes de programación, e incorporaremos algunos nuevos elementos. Repasaremos los condicionales, trabajaremos con una variable incremental y con una instrucción generadora de números aleatorios.

Descargar el código fuente del juego


Audio


Analizando un script sencillo:

En este audio repaso un poco algunos conceptos trabajados en publicaciones anteriores, y agrego algunas cosillas que creo pueden ser de interés. Como Crear una lista de atajos de teclado en una ventana gui. Agregar un comando para suspender. El uso de un condicional con una variable.
Primero comparto el script analizado en el audio:

Descargar el código fuente

Audio


Compactando el código con el uso de arrays y variables integradas:

A medida que vamos avanzando con el aprendizaje del lenguaje, es conveniente tratar de evitar las repeticiones de código. Esto va a ahorrarnos bastante escritura, así como facilitarnos la corrección de fallos. Una herramienta fundamental para este menester es el uso de las funciones, tratadas en un artículo anterior. Asimismo podemos compactar más aún el código si utilizamos arrays con datos, y variables integradas.


Arrays:

Hasta el momento solo hemos trabajado con variables simples que contenían tan solo un tipo de dato específico, los strings o cadenas de texto. Sin embargo, al igual que en todos los lenguajes de programación, existen otros tipos de datos que pueden ser contenidos en una variable. Uno de ellos son las arrays. Las arrays son un conjunto de datos contenidos en una misma variable y los cuales serán identificados por un número de índice. AutoHotkey trabaja con 3 tipos de arrays fundamentales, que dependiendo de la función que van a cumplir pueden ser conveniente usar unos, u otros. Para esta función que quiero mostrar, utilizaremos las arrays simples, que son las más sencillas. Para guardar contenido dentro de ellas, tan solo basta con escribir los datos entre corchetes, y los valores separados por comas, de esta forma:

Nombres := ["Mateo", "Milena", "Tomás", "Pedro"]


En este ejemplo guardamos en la variable Nombres un conjunto de datos separados por comas, que al ser cadenas de texto deben ir entre comillas. Como dije anteriormente estos datos van a tener asignado un número de índice el cual los va a diferenciar entre si. por lo que Mateo va a tener el número de índice 1, Milena el 2, y así sucesivamente. Para recuperar el dato de un array debemos llamar a la variable, seguida del número de índice entre corchetes:

Nombres[1]  Devuelve el nombre Mateo
Nombres[2] Devuelve el nombre milena.

De esta misma manera podríamos guardar no solo cadenas de texto sino también números, coordenadas, otras variables, etc. Vámos con un ejemplo sencillo, el cual pueden pegar en un archivo ahk vacío:

Frutas := ["Manzana", "Pera", "Banana", "Durazno", "Naranja"]


^+f::
MsgBox % Frutas[2]
Return


Esc::ExitApp

En este ejemplo, al pulsar el atajo control, shift f, nos va a devolver el contenido de la variable Frutas en la posición 2. podemos cambiar ese número entre corchetes y volver a ejecutar para comprobar el resto de datos del array.


Para profundizar en el tema Arrays, en la página de AHK encontrarán la información necesaria.

Arrays in AHK

Built-in variables:

Una cuantiosa variedad de variables útiles están integradas en el programa y cualquier script puede hacer referencia a ellas.
Con la excepción de Clipboard , ErrorLevel y los parámetros de la línea de comandos , estas variables son de solo lectura; es decir, su contenido no puede ser alterado directamente por el script. Por convención, la mayoría de estas variables comienzan con el prefijo A_, por lo que es mejor evitar usar este prefijo para sus propias variables.
Algunas de ellas son:

A_DD  Devuelve el día actual
A_mm  Devuelve el mes actual.
A_YYYY Devuelve el año actual.


Si colocamos lo siguiente en un script;

MsgBox % A_Hour ":" A_Min

Va a devolvernos la hora y los minutos actuales. Al ser un llamado a la variable por expresión, es decir que hay un espacio o más entre el signo de porciento y las variables, los strings deben ir entre comillas. Y entre los strings y las variables debe de haber al menos un espacio para que se produzca la concatenación.
De esta misma manera tenemos un montón de otras variables integradas, sin embargo las que nos interesa en este caso son las referidas a los menús, que son las siguientes:

A_ThisMenu  Devuelve el nombre del menú desde donde fué llamado.
A_ThisMenuItem  Devuelve el nombre del ítem del menú que fué ejecutado.
A_ThisMenuItemPos  Devuelve el número de posición de ese ítem del menú que fué ejecutado.


Un ejemplo sencillo para copiar y pegar:

Menu, Roy, Add, Alfa, Etiqueta
Menu, Roy, Add, Beta, Etiqueta
Menu, Roy, Add, Gama, Etiqueta
Menu, Roy, Add, Delta, Etiqueta
Return


^+t::
    Menu, Roy, Show
Return


Etiqueta:
MsgBox % "Has seleccionado la opción " A_ThisMenuItem ", del menú " A_ThisMenu ". En la posición " A_ThisMenuItemPos

ExitApp


Todo esto metido en una función:

Ahora veamos como podemos utilizar las herramientas anteriores para compactar un script. Vamos a crear un menú que contenga los nombres de los programas, y una función que contenga un array con los nombres claves de los programas y la ejecución de los mismo según su número de índice.
Primero creamos los ítems del menú;

Menu, App, Add, Block de notas, Programas
Menu, App, Add, Google Chrome, Programas
Menu, App, Add, Microsoft Edge, Programas
Menu, App, Add, Mezclador de volúmen, Programas
Menu, App, Add, Sonido de Windows, Programas

Ahora creamos la llamada al menú:

^+p::Menu, App, Show

Ahora lo interesante, vamos a construir la función con el array. En primer lugar colocamos el nombre, y entre paréntesis los parámetros con los que va a trabajar esta función, que van a ser las variables integradas del menú. Al estar como parámetros de función, no es necesario llamarlas con el prefijo A_. Quedaría así:

Programas(ItemName,ItemPos,MenuName) {
                algunas instrucciones
                }


En el menú ejecutar de windows que se abre con windows r, podemos abrir todos estos programas escribiendo su nombre clave. Para el block de notas por ejemplo se escribe "notepad", y al pulsar intro se va a abrir el programa. Estos nombres son los que guardaremos dentro del array.

Programs := ["notepad","chrome","msedge","sndvol","mmsys.cpl"]

Ahora meteremos en una variable el nombre de la aplicación que pulsamos en el menú. Para ello llamaremos al array Programs y entre corchetes le pasaremos la variable integrada ItemPos, la cual contendrá el número de posición del ítem del menú que equivaldrá al índice del array que buscamos.

App := Programs[ItemPos]

Y por último, si no se han desmayado antes, añadiremos la función Run a la que le pasaremos como parámetro esta variable que contiene el nombre del programa asignado.

Run %App%

Es un tema bastante mas avanzado de lo que veníamos trabajando, así que no desesperéis si han quedado más dudas que certezas. De a poco se irán comprendiendo los entresijos de este lenguaje. Aquí un rar con los ejemplos trabajados.

Descargar el archivo con los ejemplos


Script Creator:

La idea de esta herramienta es brindar la posibilidad de crear scripts simples, para resolver inconvenientes de accesibilidad en windows. Dentro del mundo de la programación, AutoHotkey facilita mucho la incursión al código por su simpleza y su fácil aplicación. Este script creará un archivo con el código base, donde se irán guardando las coordenadas de pantalla a las cuales podremos agregarle atajos de teclado para su fácil acceso. También podemos compilar el archivo en formato exe, para su ejecución en un sistema que no cuente con el AutoHotkey.
El script lo pueden encontrar en la sección Scripts:

Ir a la publicación del script


Audio


Plantilla AHK para la gestión de atajos de teclado:

Una de las cosas un poco incómodas de programar a la hora de hacer scripts en AHK es la gestión de los atajos de teclado.
Hay que crear ventanas con la lista, unas cuantas funciones para poder permitir que los usuarios cambien estos atajos y varias cosas más. Por eso surgió la idea de crear una plantilla genérica, la cual podremos utilizar en cualquier script que hayamos creado o vayamos a crear.
La idea es que con una lista de comandos del script, y un par de includes ya se puede tener estas funciones totalmente listas para usar. Tanto la gestión con ventanas incluídas, como las funciones de verbalización de NVDA o Jaws. Dejo el link del proyecto en github. Que por cierto, los que aún no utilizan git, los invito ferbientemente a que aprendan su manejo ya que es una herramienta fundamental de desarrollo.

Publicación sobre el programa de control de versiones git
repositorio AHK-template en github
Descarga de la plantilla en zip>


audio:

En el siguiente audio ejemplifico la aplicación de esta plantilla en un script simple

Descargar el script del tutorial


Uso de las arrays para la recreación de una interfaz inaccesible:

La recreación de una interfaz inaccesible requiere de bastante programación e ingenio. Mientras más compleja sea la ventana a recrear, más complejo se vuelve el código necesario.
En este primer audio sobre este tema veremos el uso de una variable incremental, repasaremos el concepto de array, y crearemos un código simple para iterar entre los elementos y realizar acciones.
En el siguiente link pueden descargar un archivo comprimido que contiene los 5 ejemplos utilizados: Descargar los ejemplos


Audio: