• Última versión: febrero de 2018 para NVDA 2018.1

Esta guía fue escrita originalmente por Joseph Lee, y está diseñada por la comunidad de usuarios y de desarrolladores de NVDA. Agradecemos vuestros comentarios y contribuciones.

NVDA es copyright 2006-2018 NV Access Limited. Microsoft Windows, Microsoft Office, Win32 API y otros productos de Microsoft son propiedad de Microsoft Corporation. el paquete IAccessible es propiedad intelectual de IBM y la Fundación Linux. Python es propiedad intelectual de la Python Software Foundation. Otros productos mencionados son propiedad intelectual de sus respectivos propietarios.

Introducción

Bienvenido a la Guía de desarrollo de complementos para NVDA. Esta es la guía completa sobre cómo desarrollar complementos de NVDA. Esta guía también explica algún segmento de código útil del código fuente del núcleo de NVDA, que resalta conceptos para ti mientras aprendes a escribir complementos.

Para obtener más información sobre el desarrollo de NVDA, por favor visita la Página de la Comunidad de Desarrollo de NVDA. Asegúrate de revisar la Guía del desarrollador de NVDA para familiarizarte con los términos clave y los conceptos básicos para comenzar con el desarrollo de complementos.

Audiencia

Esta guía se ha diseñado para:

  • aprendices de Python
  • aprendices de NVDA
  • desarrolladores Expertos de Python
  • desarrolladores Expertos de NVDA
  • Gente familiarizada con otros lenguajes de programación distintos a Python.
  • Desarrolladores de scripts para otros lectores de pantalla.

Si eres nuevo en el desarrollo de complementos o del núcleo de NVDA, te recomendamos que conozcas Python primero, ya que proporciona los conocimientos de programación necesarios para entender el resto de la guía. Si eres programador de Python pero eres nuevo en el desarrollo de NVDA, por favor, consulta la guía de desarrollo de NVDA y el documento Vista General de Diseño, los cuales se encuentran en la página de la comunidad de desarrolladores de NVDA.

Nota especial sobre la versión de Python

NVDA y los complementos están escritos en Python 2, específicamente 2.7. Existe un proyecto de investigación activo para transferir NVDA a python 3, con algunos desarrolladores de complementos modificando su código fuente para que se ejecute en Python 2 y 3. Asegúrate de estar atento al desarrollo de NVDA y a las listas de correo de complementos, así como a la documentación de desarrollo relevante y a los avisos relacionados con las noticias sobre Python 3 y NVDA.

Una nota especial para creadores de scripts de otros lectores de pantalla

Algunos de los conceptos descritos en este documento son los mismos para diferentes lectores de pantalla, tales como objetos, ventanas, eventos, APIs de accesibilidad y así sucesivamente. Sin embargo, hay cosas importantes que hay que tener en cuenta al escribir o portar scripts:

  • A diferencia de algunos lectores de pantalla, NVDA no tiene una especificación formal o un modelo de objeto definido por la documentación en otros lectores de pantalla.
  • El código que escribas se ejecutará dentro del mismo entorno de ejecución que el propio lector de pantalla, por lo que puedes realizar cosas como obtener directamente objetos enfocados, modificar la funcionalidad de NVDA e incluso reemplazar las funciones y clases de NVDA con las tuyas propias.
  • Python, y consecuentemente NVDA, es un sistema orientado a objetos. En otras palabras, la mayor parte de su código consistirá en definir clases y objetos que NVDA recogerá en tiempo de ejecución.
  • A diferencia de los motores de scripting para algunos lectores de pantalla, no hay ningún hack especial involucrado cuando se desee proporcionar una característica que funcione en todas las aplicaciones.
  • A diferencia de los motores de scripting para algunos lectores de pantalla, no estás limitado a bibliotecas que vengan con los lectores de pantalla; como un programa basado en Python, puedes usar cualquier módulo (s) de python que se adapte a tus necesidades. Por ejemplo, un módulo popular utilizado para interactuar con aplicaciones web es el módulo JSON (JavaScript Object Notation), que no está incluido en las versiones de NVDA anteriores a 2017.3. Necesitas incorporar las bibliotecas externas de Python tú mismo.

Nota especial sobre la versión de NVDA para la tienda de Windows

A partir de NVDA 2018.1, se han establecido cambios para permitir a NVDA ejecutarse como una aplicación de la tienda Windows. Una vez se publique en la tienda la versión de NVDA para la tienda de Windows, los usuarios de Windows 10 podrán ir a la tienda y obtener NVDA. Sin embargo, hay restricciones que vienen con esta versión de NVDA, la más notable es que los complementos no pueden ejecutarse en este entorno. Por lo tanto, si necesitas ejecutar o escribir complementos de NVDA, deberás utilizar la versión clásica de escritorio de este lector, disponible en la sección de descargas de nuestro sitio web.

¿Qué son los Complementos?

Los complementos son paquetes adicionales que amplían la funcionalidad de NVDA o el soporte para programas. Esto puede incluir la adición de características globales, la mejora de la compatibilidad con una aplicación o la adición de soporte para nuevas pantallas braille o sintetizadores de voz. Los complementos pueden contener más de un módulo. A continuación se incluye una descripción general de los tipos de módulos adicionales.

Tipos de módulos de Complementos

Actualmente, NVDA soporta estos tipos de módulos adicionales:

  • Extensión global: una extensión global añade características para NVDA que se pueden utilizar en cualquier lugar, como la función de OCR.
  • Módulo de aplicación: Un módulo de aplicación permite un soporte mejorado para un programa específico. Los módulos de aplicación sólo se ejecutan mientras el programa se ejecute. Cambian la forma en que NVDA reacciona a las ventanas y controles de la aplicación en ejecución.
  • Controlador: Un controlador permite a un programa comunicarse con el hardware. Actualmente puedes escribir controladores para nuevas pantallas braille o sintetizadores de voz.

Instalación de Complementos de NVDA

Cada paquete de complementos de NVDA es un archivo zip con la extensión de archivo .nvda-addon. Puedes instalar módulos adicionales a través del Administrador de complementos en NVDA 2012.2 o posterior. Alternativamente, puedes instalarlos desde el Explorador de Archivos si utilizas NVDA 2012.3 o posterior.

Configuración del entorno de desarrollo de complementos

Sigue estos pasos para preparar tu ordenador para escribir complementos de NVDA.

Cumplir con los requisitos del Sistema

Para crear un complemento para NVDA, asegúrate de que tu sistema cumple los siguientes requisitos:

  • Una versión de NVDA está disponible en tu ordenador (funcionará ya sea una versión portable o instalada, pero te recomendamos encarecidamente que instales una copia de NVDA en tu ordenador de desarrollo). Descarga NVDA desde la página de NV Access en https://www.nvaccess.org.
    • Recomendamos instalar la última versión master de desarrollo para mantenerse al día con los cambios en el API del núcleo. Puedes descargar las últimas snapshots en https://community.nvda-project.org/wiki/Snapshots.
  • Series de Python 2.7, versión 2.7.14 32-bit para Windows: https://www.python.org/download/releases/2.7.14/.
  • SCons 2 o 3, versión 2.3.0 o posterior para la generación de paquetes de complementos (si se usa la versión 3.x, se recomienda la 3.0.1 o posterior): http://www.scons.org/.
  • Markdown 2.0.1 o posterior para generar la documentación del complemento: https://pypi.python.org/pypi/Markdown/2.0.1.
  • El paquete Gettext de GNU para Windows para soporte de localización de mensajes. La compilación se puede encontrar en: http://gnuwin32.sourceforge.net/downlinks/gettext.php.
    • Una vez descargados, copia ambos archivos exe en la carpeta de desarrollo del complemento. Consulta la siguiente sección para obtener una descripción de la estructura de carpetas del complemento.
  • Git 1.7.9 o posterior si deseas subir el complemento a un repositorio como Bitbucket (opcional). Puedes utilizar varios clientes de Git, como Git Bash, Git de Cygwin, y Tortoise Git.
  • La plantilla de complemento de NVDA de la comunidad para facilitar el empaquetado y la gestión de carpetas y archivos del complemento (opcional) Descarga la plantilla del complemento).
  • Si estás desarrollando soporte para un programa, sintetizador de voz o pantalla braille, instala el software y el hardware necesario.

Nota: si utilizas Windows 10 Anniversary Update o posterior y deseas usar Ubuntu en Windows (también conocido como Windows Subsystem for Linux), puedes utilizar Advanced Packaging Tool (APT) para obtener SCons y Gettext. A continuación, puedes utilizar pip para descargar e instalar Markdown.

Estructura de Carpetas de Desarrollo del Complemento

Cuando escribas complementos, se recomienda que guardes el código del complemento en carpetas separadas, una por complemento. Si decides descargar la plantilla del complemento, la estructura de carpetas se creará automáticamente.

Una vez que instales las dependencias necesarias (mira arriba), pega los ejecutables del paquete Gettext en la carpeta del complemento.

Estructura de carpetas del complemento

Cada carpeta de complementos, como mínimo, debe contener los siguientes archivos y carpetas:

  • manifest.ini para almacenar la información de manifiesto del complemento tal como el nombre y el autor.
  • Una subcarpeta “addon” con el directorio de módulos del complemento bajo esta subcarpeta (appModules, globalPlugins, synthDrivers, brailleDisplays). Se pueden especificar una o más carpetas de módulos.

Si estás utilizando la plantilla de complementos, la estructura de carpetas se creará automáticamente, por lo que sólo necesitas crear la subcarpeta addon y las carpetas de módulos adicionales y el código dentro de estas carpetas. Consulta el archivo readme en la carpeta de la plantilla para obtener más información sobre cómo personalizar tu manifiesto de complemento mediante los archivos de la plantilla.

Enpaquetado de complementos

Hay dos modos de empaquetar complementos:

  1. Para empaquetar el complemento manualmente, comprime (en zip) la carpeta del complemento como un archivo .zip, y luego cambia el nombre de la extensión del archivo a .nvda-addon.
  2. Para utilizar la plantilla de complemento con SCons, abre el símbolo del sistema en el modo Administrador (Windows Vista o posterior) o Bash en Ubuntu en Windows (Windows 10 Anniversary Update con el WSL habilitado), cambie a la carpeta de complemento y escribe `scons~.

Para más información sobre gestión de complementos, consulta el capítulo gestión en esta guía.

Comenzando: Ejemplos prácticos

Entonces, ¿estás listo para comenzar tu aventura con los complementos, pero no estás seguro de cómo darle vida? Si ese es tu caso, vé por favor a través de este capítulo, pues te da la información básica para conseguir comenzar con los complementos y te da consejos para escribir código.

Nota: para este capítulo, no usaremos paquetes de complementos reales. En su lugar, usaremos carpetas de extensiones – una serie de subdirectorios en tu carpeta de configuración de usuario de NVDA (disponible desde el menú de inicio/pantalla si está instalado NVDA) para almacenar nuestros ficheros Python de ejemplo.

Para editar archivos .py, necesitas un procesador de textos que pueda manejar archivos .py. El mejor que recomendamos es Notepad++ que se puede descargar de https://notepad-plus-plus.org/download/v6.8.3.html.

Cómo está organizado el código de los complementos

El código de tu complemento se almacena en uno o más ficheros Python (fichero .py). A pesar de los diferentes tipos de complementos que hay por ahí, todos ellos tienen un diseño similar.

Primero, comienza por escribir una cabecera opcional para el complemento, tal como tu nombre, una o dos frases breves sobre para qué es el complemento y así sucesivamente. Aunque esto es opcional, Se recomienda que escribas el encabezado como un recordatorio para realizar un seguimiento de lo que estás haciendo con tu complemento.

A continuación, le dices a NVDA los módulos que necesitas para el complemento en el archivo. Esto se hace escribiendo import module donde module es el nombre del módulo que desees utilizar en tu código. Por ejemplo, si quieres escuchar tonos mientras escribes tu complemento, escribe import tones. Normalmente será posible que tengas que importar dos o más módulos para tu complemento específico(véase más abajo en la lista de módulos que necesitas para el tipo de módulo del complemento que estés escribiendo).

después de declarar los módulos necesarios o de importar, escribe el código de tu complemento (definiendo clases, variables, métodos y así sucesivamente). La sección más importante es el código de la clase del complemento, que determinará el tipo de módulo de complemento al que se asignará tu código.

Por ejemplo, si deseas agregar soporte para un programa, después de importar appModuleHandler y otros módulos necesarios, podrías escribir:

class appModule(appModuleHandler.AppModule):

Después de eso, todo lo que se escribe es código Python (consulta la documentación de Python sobre cómo escribir programas en Python).

Ejecutar tu complemento de ejemplo en este capítulo

Para ejecutar tu complemento de ejemplo desde este capítulo, abre el directorio de configuración de usuario de NVDA(desde Menú o pantalla Inicio, busca el elemento NVDA ” buscar Explorar carpeta de configuración del usuario). Luego pega tu fichero .py en la carpeta correspondiente: carpeta appModules para ejemplos de módulos de aplicación, y carpeta globalPlugins para extensiones globales.

Ejemplo 1: escuchar un tono al pulsar NVDA+A

Comencemos con un ejemplo sencillo: Si pulsamos NVDA+A, se oye un tono durante 1 segundo desde cualquier programa. Puesto que queremos usar esto en todas partes, debe ser una extensión global.

En primer lugar, abre la carpeta de configuración de usuario, a continuación, abre la carpeta globalPlugins. Crea un nuevo fichero .py y dale un nombre descriptivo, como example1.py (se recomienda encarecidamente que cuando le dés el nombre del fichero de la extensión global, este sea corto). A continuación, abre el archivo .py recién creado en el procesador de textos.

El código siguiente implementa nuestro ejemplo. Pon esto en tu .py exactamente como se muestra.:

# Primer ejemplo de desarrollo de complemento

import globalPluginHandler
import tones # Queremos escuchar pitidos.

class GlobalPlugin(globalPluginHandler.GlobalPlugin):

    def script_doBeep(self, gesture):
        tones.beep(440, 1000) # pita un Lá estándar de la quinta octava durante 1 segundo.

    __gestures={
        "kb:NVDA+A":"doBeep"
    }

En Python, para poner comentarios se pone el símbolo número (#) al principio de la línea de comentario.

Explicación del código del ejemplo 1

Nuestro primer ejemplo nos permite hacer sonar un pitido durante un segundo cuando pulsemos NVDA+A. pero podrías preguntarte sobre el significado del código de más arriba, así que vamos a dar unos pasos a través del código, uno por vez.

  1. En la parte superior del archivo, escribimos una cabecera que nos dice que este es un ejemplo de complemento.
  2. Dado que esta es una extensión global, tenemos que importar un módulo fundamental: global plugin handler, por lo que escribimosimport globalPluginHandler.
  3. Entonces escribimosimport tones para importar (cargar, o incluir) el módulo de tonos, un módulo integrado de NVDA. Cada vez que desees utilizar un método de un módulo dado, importa el o los módulos necesarios.
  4. A continuación, definimos una clase llamada GlobalPlugin. El texto dentro de los paréntesis nos dice de dónde proviene esta clase (más sobre este concepto en un segundo). Una clase, en programación, describe un objeto, tal como una persona, un escritorio, un programa y otros.
  5. Dentro de la clase, escribimos un método (función) llamado script_doBeep. Esto es un ejemplo de un script, un método que va a ejecutarse al pulsar una orden. Dentro de este script, escribimos tones.beep(440, 1000) para decir a NVDA que haga sonar un tono durante 1 segundo. En programación, una funcción puede tomar argumentos, o un conjunto de parámetros que dice a la función qué hacer basándose en los valores dados(nos los encontraremos más adelante). De hecho, muchos métodos que escribirás, incluyendo nuestro script doBeep toma uno o más argumentos. Más sobre los scripts más tarde en el viaje a través de la guía.
  6. Por último, escribimos un diccionario simple (una colección) para almacenar enlaces a nuestra orden (script) para nuestro script doBeep. Aquí, le dijimos a NVDA que asignase NVDA+A command para el script doBeep.

Guarda este fichero, después reinicia NVDA. Ahora, cada vez que se pulse NVDA+A, se escucha un tono durante 1 segundo. Una vez que te sientas cómodo con el código del complemento y de cómo se presenta, Puedes eliminar el fichero .py recién creado.

No entiendo los términos anteriores

Para algunos, los términos “clase”, “método” y demás podrían ser nuevos. Vamos a repasar lo que son estos términos, ya que son fundamentales para el desarrollo de complementos:

Clase: una clase describe un objeto. Podría describir cualquier cosa, tal como una persona, una mesa, un complemento de NVDA y otros. Las clases son fundamentales para NVDA y otros programas – de hecho, un buen número de programadores son expertos por conocer las clases.
Método: un método es un pequeño programa o una rutina que ejecuta un programa para hacer algo, tal como generar tonos, calcular números grandes, cargar complementos de NVDA y así sucesivamente. Algunas personas los llaman “funciones.”
Script: un script es un método que se ejecuta cuando el usuario realiza órdenes tales como pulsar ciertas teclas en un teclado. Por ejemplo, cuando pulsas NVDA+F12, NVDA ejecuta el script dateTime, localizado en uno de los módulos principales de NVDA llamado Global Commands. Un script toma dos argumentos: dónde se debería ejecutar el script (normalmente “self”; lo veremos más adelante) y el gesto para el script (véase más adelante).
Variable: una variable es algo que puede cambiar, tal como el nombre de una persona, un nombre del complemento de NVDA en ejecución, la versión de NVDA que estás utilizando y así sucesivamente. En un archivo de complemento pueden definirse una o más variables(Por ejemplo, para almacenar constantes comunes, tales como cadenas).
Módulo: un módulo es una colección de métodos y variables en un fichero. Cuando escribimos complementos, de hecho, estamos escribiendo módulos adicionales que NVDA puede utilizar mientras se está ejecutando.

Hay otros términos que vamos a llegar a conocer en breve.

Ejemplo 2: generar un tono cuando se cambie al Bloc de notas

La mayor parte del código de abajo viene de la Guía del desarrollador de NVDA.

NVDA no sólo te permite agregar comandos globales, sino que también permite la escritura de código para mejorar el uso de los programas a través de módulos de aplicación. Un módulo de aplicación es también un archivo Python, excepto que, esta vez, el nombre del archivo .PY Es el nombre del ejecutable de un programa. Por ejemplo, un módulo de aplicación para el Bloc de notas se llamaría notepad.py.

El código de abajo, de la Guía del desarrollador de NVDA, da un pequeño ejemplo de un módulo de aplicación típica: reproducir un pitido corto al cambiar al Bloc de notas. Pon el código de abajo en notepad.py, que a su vez se debe colocar en la carpeta appModules en la carpeta de configuración del usuario con el fin de que se ejecute.

# Un ejemplo de módulo de aplicación.

import appModuleHandler
import tones

class AppModule(appModuleHandler.AppModule):

    def event_gainFocus(self, obj, nextHandler):
        tones.beep(256, 200)
        nextHandler()

Explicación del código del ejemplo 2

Estamos viendo más código nuevo aquí. Vamos a repasar esto, de nuevo pieza por pieza:

  1. A diferencia del primer ejemplo, el módulo fundamental que necesitamos es appModuleHandler.
  2. La clase que estamos utilizando es appModule.
  3. A diferencia de la última vez, estamos utilizando eventos, un método que se ejecuta cuando se producen determinados eventos, como cuando los nombres de los controles cambian. Los eventos reciben un objeto como uno de sus argumentos, el objeto para el que el evento debe ser tratado, o, como mucha gente dice, “disparado.”
  4. Dentro del método de evento, también estamos viendo una llamada anextHandler. Este método se utiliza en métodos de evento para decirle a NVDA que pase el evento para que pueda ser atendido, tal como decir el nombre de un control después de sonar.

Más términos nuevos por favor

Otros términos que puedes ver son:

  • Evento: un evento es un método que va a ser ejecutado cuando sucedan algunos hechos, tales como cuando un programa esté enfocado, cuando cambien los nombres de un control y así.
  • Llamada: decimos que una función llama a algún otro método cuando corremos el segundo método desde otro método. Por ejemplo, en nuestro primer ejemplo, llamábamos al método tones.beep desde nuestro método de script.
  • Objeto: un objeto es una instancia de una clase- es decir, una clase que se crea cuando se ejecuta un programa. A lo largo de tus complementos, a medida que escribes las clases y al ejecutar tus complementos, tus clases cobran vida como objetos, comúnmente abreviados como obj. En NVDA, un objeto puede referirse a los controles o partes de un programa.
  • Self: en Python, la palabra”self” significa clase actual(si estamos definiendo una, como por ejemplo al escribir complementos), o significa la clase para la que se define un método. Por ejemplo, en una clase llamada numbers, el método añadido tendría a self como su primer argumento, recordándonos que el método añadido es parte de la clase numbers. En el mundo de desarrollo de NVDA, self por lo general significa el objeto actual de NVDA (véase más adelante), o en el desarrollo de complementos, la instancia de un complemento. Muchos de tus métodos tendrán a self como el primer argumento.

Al igual que en el ejemplo 1, una vez te sientas cómodo con el código del módulo de aplicación, es posible que desees eliminar este código para el Bloc de notas, a menos que desees mantener el oír pitidos cuando se cambie al Bloc de notas. Las diferencias reales entre extensiones globales y módulos de aplicación se harán más claras cuando hablemos de ellos con más detalle en esta guía.

Algunos consejos para principiantes

Aquí van algunos consejos útiles transmitidos por escritores de complementos:

  • Comienza con complementos sencillos, como decir un mensaje, tonos, etc.
  • Escribe y prueba un método por vez.
  • Si estás escribiendo módulos de aplicación o controladores, familiarízate con los programas, sintetizadores o pantallas braille a las que desees dar soporte (por ejemplo lee la documentación, trata de usarlos, etc.).
  • En la definición de las órdenes (especialmente en extensiones globales), primero consulta las órdenes utilizadas en NVDA y otros complementos antes de asignar una nueva orden en el complemento para evitar conflictos de órdenes.

Módulos útiles del núcleo de NVDA

A lo largo de la vida del desarrollo de un complemento, te encontrarás con algunos módulos útiles del núcleo de NVDA que serían útiles en el código para tu complemento. Esta sección te los explica y también algunas funciones.

Nota: para lectores que sean creadores de scripts para otros lectores de pantalla, consultad el Apéndice D sobre las funciones equivalentes entre las herramientas de creación de scripts de lectores de pantalla.

Lista de módulos y métodos básicos útiles de NVDA

A continuación se enumeran los módulos disponibles del núcleo de NVDA y algunos métodos útiles que se encuentran en los módulos:

  • Addon Handler (addonHandler.py): El módulo que implementa el subsistema de complementos. El método addonHandler.initTranslation() se utiliza para inicializar el soporte de internacionalización para tu complemento.
  • API básica de NVDA (api.py): una colección de los métodos básicos utilizados en NVDA, como la obtención del foco y el navegador de objetos, ajustar el foco, etc. Algunas de las funciones más útiles son:
    • api.getFocusObject(): recupera el control enfocado (devuelve el objeto con el foco).
    • api.getNavigatorObject(): obtiene el navegador de objetos actual. Si NVDA está configurado para seguir al foco del sistema, el foco y el navegador de objetos serán lo mismo, de otro modo se devuelve un objeto diferente.
    • api.getForegroundObject(): devuelve la ventana en primer plano de la aplicación actual (el padre de este objeto es la aplicación misma).
    • Estos tienen un método correspondiente para establecer un objeto determinado como el foco o el navegador de objetos. Ten en cuenta que esto permite a NVDA consultar el foco o el navegador de objetos nuevo pero no cambia el foco actual del sistema.
    • api.getDesktopObject(): devuelve la shell (objeto del nivel más alto).
    • api.copyToClip(): copia texto en el portapapeles.
  • Subsistema de módulos de aplicación (appModuleHandler.py, appModules): El subsistema encargado de manejar los módulos de aplicación (véase el capítulo sobre los módulos de aplicación para obtener más información).
  • Soporte de ARIA (aria.py): implementa el soporte para aplicaciones de Internet enriquecidas accesibles (ARIA).
  • Colección de objetos base (baseObject.py): contiene objetos base útiles tales como objetos scriptables (consulta el capítulo sobre objetos de NVDA y superposición de objetos para más información).
  • Subsistema de entrada y salida braille (braille.py, brailleInput.py): controla la salida y la entrada braille de las pantallas braille, necesario para complementos de controladores de pantallas braille.
  • Módulos integrados (builtin.py): permite el acceso a módulos integrados cuando se trabaja con complementos.
  • Configuración (config): gestiona la configuración y los perfiles (los perfiles están disponibles en 2013.3 o posterior).
  • Colección de controles y estados (controlTypes.py): incluye diccionarios sobre los tipos de control (roles) y posibles estados.
  • Eventos (eventHandler.py): maneja varios eventos como la optención del foco. Una función en particular es útil en los módulos de aplicación:
    • eventHandler.requestEvents(process ID, window class name for the control, event to be requested): Permite a NVDA escuchar eventos específicos para ciertos controles mientras se utiliza otra aplicación.
  • Puntos de extensión (extensionPoints.py): proporciona una forma de permitir que los complementos y otros módulos definan y respondan a acciones específicas como cambios de perfil, acciones en un complemento, etc. Se definen los siguientes puntos de extensión:
    • extensionPoints.Action; notifica cuando algo ocurre, por ejemplo: el perfil cambia.
    • extensionPoints.Decider: decide si procesar algo más, por ejemplo: procesar la entrada del teclado desde un sistema remoto.
    • extensionPoints.Filter: modifica un texto determinado para su procesamiento posterior, por ejemplo, secuencias avanzadas de voz.
  • Colección de Comandos globales (globalCommands.py): Una lista de las órdenes globales disponibles durante el uso de NVDA (véase la sección sobre el alcance de un script para más información).
  • Subsistema de extensiones globales (globalPluginHandler.py): El módulo necesario para controlar las extensiones globales.
  • GUI de NVDA (gui): Una colección de clases utilizadas por NVDA para mostrar sus mensajes de forma gráfica. Incluye la interfaz gráfica de usuario para el menú de NVDA, el administrador de complementos y otros.
  • Servicios de los puertos Hardware(hwPortUtils.py): Un conjunto de utilidades para la comunicación a través de los puertos serie de hardware y otros, útil durante el desarrollo de un complemento de controlador.
  • Soporte para IAccessible (IAccessibleHandler.py, objetos IAccessible): Se utiliza para dar soporte a los controles IAccessible.
  • Gestión de entrada (inputCore.py): Gestiona la entrada del usuario.
  • Soporte de Java Access Bridge (JABHandler.py): Una colección de los métodos utilizados para soportar el subsistema JAB utilizado por las aplicaciones Java.
  • Entrada de teclado (keyboardHandler.py): Soporta la introducción de órdenes desde el teclado.
  • Función de registro (logHandler.py): Permite a un módulo escribir registros para ser vistos por un desarrollador o por un usuario a través del visualizador de registro. Incluye la siguiente clase:
    • logHandler.Log: la clase que implementa la utilidad de registro.
  • Presentación de contenido matemático (paquetes de MathPress): permite a NVDA reconocer e interactuar con diversos contenidos matemáticos y marcas de revisión. NVDA se envía con el paquete de soporte MathML y el soporte para Math Player se incluye en 2015.2 o posterior.
  • Soporte de ratón (mouseHandler.py): Soporta órdenes de ratón.
  • Colección de objetos de NVDA (NVDAObjects): Una colección de objetos o controles de NVDA que se utilizan en muchas aplicaciones y estándares como la UIA (User Interface Automation). Algunos objetos requieren que se realicen acciones especiales y éstas se especifican en el módulo de comportamientos del paquete de objetos NVDA. Entre los más comunes se incluyen:
    • NVDAObjects.NVDAObject: la clase base para objetos de NVDA donde se definen eventos, propiedades, etcétera.
    • NVDAObjects.IAccessible: una colección de objetos MSAA/IAccessible, tales como la que funciona con vistas de listas SysListView32 y otros.
    • NVDAObjects.JAB: una colección de clases utilizadas al interactuar con aplicaciones Java y Java Access Bridge.
    • NVDAObjects.UIA: varias clases para objetos impulsados por UI Automation. Desde 2016, también es el sitio de una colección de controles usados en Microsoft Edge y objetos promovidos por el motor de renderizado EdgeHTML.
    • NVDAObjects.Window: ventanas genéricas y otros objetos personalizados como los que se encuentran en Microsoft Excel.
    • NVDAObjects.behaviors: una colección de comportamientos para controles específicos, tales como editar campos con o sin detección de selección, terminales, consejos, globos de ayuda, una forma de simular órdenes de tabla en varios controles y otros.
  • Facilidad de revisión (review.py): ayuda a trabajar con el cursor de revisión.
  • Soporte de Scripts (scriptHandler.py): Maneja scripts, métodos ejecutados debido a la pulsación de las órdenes de teclado y otras entradas.
  • Salida de voz(speech.py): Controla la salida de voz.
  • Soporte para controladores de Sintetizador (synthDriverHandler.py): Este es el módulo principal necesario para complementos de sintetizador de voz.
  • Acceso al texto de los Widgets (textInfos): Permite el acceso al texto de widgets y documentos.
  • Soporte de pantalla táctil (touchHandler.py): Proporciona soporte para la entrada de la pantalla táctil (sólo versiones instaladas).
    • touchHandler.touchSupported() (NVDA 2018.1 o posterior): indica si el sistema soporta interacción táctil.
  • Salida de tonos (tones.py): Permite al usuario escuchar tonos. Se definió la siguiente función:
    • tones.beep(tono en hercios, duración en milésimas de segundo, volumen del canal izquierdo, volumen del canal derecho): Reproduce un sonido de un tono específico durante un tiempo determinado. Los dos primeros argumentos son obligatorios, mientras que los otros dos son opcionales.
  • Mensajes de la interfaz de usuario (ui.py): Incluye varias funciones para la salida de voz y/o braille, incluyendo:
    • ui.message(mensaje a ser verbalizado/braillificado): verbaliza o braillifica el mensaje. Este debe ser una cadena entre comillas.
    • ui.browsableMessage(mensaje a ser mostrado, HTML o no): muestra algún texto en una ventana del navegador web. Si deseas utilizar el marcado HTML, define el argumento isHTML como True.
  • Soporte UIA (UIAHandler.py, objetos UIA): Usado para soportar controles UIA (User Interface Automation) (Windows 7 y posteriores).
  • Mmodos virtuales(virtualBuffers): Maneja documentos del modo virtual, tales como sitios web.
  • Capas de la API de Windows: los siguientes módulos son capas delgadas de las bibliotecas de la API de Windows. Puedes utilizar los módulos siguientes o llamar a la API de Windows directamente a través de ctypes.windll.dllname (por ejemplo, ctypes.windll.user32):
    • winKernel: abarca algunas constantes, estructuras y funciones de kernel32.dll que se encuentran comúnmente en NVDA.
    • winUser: abarca las constantes, estructuras y funciones definidas en user32.dll que utiliza NVDA.

Los módulos sin extensión .py son directorios que contienen módulos especializados. Hay otros métodos útiles por ahí, además de la lista anterior, pero los anteriores son los más útiles. Consulta la documentación del código fuente de NVDA para ver otros métodos, o mira los ejemplos que aparecen a continuación para ver cómo se utilizan estos métodos y otros durante la vida de un complemento.

Ejemplo 1: ¿Estoy en la aplicación correcta donde se encuentra el foco?

El siguiente código verifica si el navegador de objetos e encuentra en algún lugar de la misma aplicación o no.

import api
import ui

def sameApp(obj=None):
    if obj is None:
        obj = api.getNavigatorObject()
    return api.getFocusObject().appModule == obj.appModule

La función api.getNavigatorObject () devuelve el objeto del navegador actual, el objeto que te interesa en lugar del objeto enfocado. Cada objeto de NVDA incluye un miembro appModule que registra en qué aplicación se encuentra un objeto.

Ejemplo 2: Mostrar un mensaje en un documento en modo exploración

Desde NVDA 2015.2 y posterior, fue posible mostrar un mensaje en una ventana del modo de exploración para que la gente pueda utilizar las órdenes del modo de exploración para revisar el contenido del mensaje. El siguiente código muestra”Hola mundo” en la ventana de un documento.

import ui

ui.browsableMessage("Hola Mundo!", isHtml=False)

La bandera isHtml indica a NVDA que trate el mensaje como un texto HTML.

Ejemplo 3: Anunciar el ID de automatización de un objeto UIA

En UI Automation, el ID de automatización se utiliza para identificar diferentes elementos de pantalla. El siguiente código muestra esta información en una ventana navegable.

import ui
from NVDAObjects.UIA import UIA

def announceUIAId():
    obj = api.getFocusObject()
    if isinstance(obj, UIA):
        UIAElement = obj.UIAElement
        ui.browsableMessage(UIAElement.cachedAutomationId, isHtml=True)

Ejemplo 4: Enviar pulsaciones de teclas

Puedes pedirle a NVDA que envíe pulsaciones de teclas específicas instanciando un objeto de gesto de teclado.

import keyboardHandler

def sendApplicationsKey():
    keyboardHandler.KeyboardInputGesture.fromName("kb:applications").send()

Ejemplo 5: Detener la voz cada vez que cambie el contenido de la pantalla si el anuncio de cambio de contenido dinámico está desactivado

El código que aparece a continuación es un controlador para un evento de cambio de nombre que detiene la voz siempre que el contenido de la pantalla cambie si el anuncio de cambio de contenido dinámico está desactivado.

import appModuleHandler
import config
import speech

class AppModule(appModuleHandler.AppModule):

    def event_nameChange(self, obj, nextHandler):
        if not config.conf["presentation"]["reportDynamicContentChanges"]:
            speech.cancelSpeech()

Esto es sólo una muestra de lo que pueden hacer varios módulos y funciones de NVDA en tu complemento. Recorreremos los componentes complementarios y realizaremos más funciones a lo largo de esta guía.

Componentes del módulo de un complemento y consejos de desarrollo

Un módulo de complemento se compone de una serie de componentes. Esto incluye el manejo de la entrada y de la salida, el trabajo con diferentes objetos de NVDA, la reacción a eventos, el almacenamiento de configuración y más.

Este capítulo presenta los componentes y conceptos clave que se utilizan en el desarrollo de complementos, tales como objetos de NVDA, scripts, gestión de eventos y temas adicionales con ejemplos.

Ten en cuenta que la guía de desarrollo básico de NVDA presenta los siguientes conceptos. Este capítulo pretende ser una extensión de ese documento. Consulta la guía de desarrollo de NVDA para una breve introducción.

Nota para creadores de scripts de otros lectores de pantalla: es posible que estés familiarizado con algunos de los conceptos introducidos en esta sección. Por favor, lee esta sección si deseas conocer mejor cómo se utilizan algunos de ellos en NVDA.

Trabajando con objetos en pantalla

Un objeto es una instancia de una clase – es decir, una clase activa mientras un programa se está ejecutando. Por ejemplo, si se ha definido una clase llamada botón, el botón en una pantalla es el objeto de esta clase botón.

En NVDA, un objeto es la representación de un control o partes de un programa. Esto incluye botones, casillas de verificación, campos de edición, barras de herramientas, deslizadores e incluso la ventana de la aplicación. Estos se organizan en jerarquías, o relación padre-hijo donde un objeto podrá contener objetos hijos – por ejemplo, un objeto lista en Windows Explorer podrá contener uno o más elementos de lista, y el padre de esta lista podría ser la ventana de Windows Explorer. El objeto que estás examinando en este momento se denomina “navegador de objetos.”

Los objetos de NVDA (o simplemente llamados objetos) contienen una serie de propiedades o atributos útiles. Estos incluyen el nombre del objeto, su valor (seleccionado, el texto de la ventana de edición, etc), rol (casilla de verificación, ventana, objeto incrustado, etc., localización (coordenadas de la pantalla) y más. Los objetos de NVDA también contienen métodos útiles para su manipulación, tales como cambiar el valor del objeto, reaccionar a los eventos para el objeto (recepción del foco, valor de cambio, etc).

En muchas situaciones, un objeto NVDA puede pertenecer a una clase de objetos relacionados. Para cada una de las clases de objetos, NVDA proporciona formas de manipularlos. Estas clases incluyen IAccessible, JAB, UIA y así. Estas clases y comportamientos para cada clase de objetos se definen en el directorio NVDAObjects en el código fuente de NVDA, y para utilizarlos en tu complemento, importa el controlador de clase de objeto adecuado para el objeto que estás utilizando(por ejemplo si estás trabajando con un objeto IAccessible, importa NVDAObjects.IAccessible.).

Dos de estas clases de objetos merecen especial mención: los modos virtuales y los interceptores de árbol. Un interceptor de árbol permite a NVDA funcionar con un “árbol” de objetos como si fuesen sólo un objeto. un caso especial de interceptor de árbol es el modo virtual, que permite a NVDA trabajar con documentos complejos, como documentos PDF. Estos objetos contienen un mecanismo especial para determinar si una orden de teclado dada será pasada a la aplicación o manejada por NVDA (por ejemplo, el modo de exploración donde se usa la primera letra de navegación para moverse entre elementos).

Examinando la jerarquía de objetos

Hay varias alternativas que puedes utilizar para ver la jerarquía de un objeto de un determinado programa:

  1. utilizando las órdenes de navegación de objetos(NVDA+2/4/5/6/8 del teclado numérico) con el modo simple de revisión desactivado.
  2. Utilizando la consola de Python, usa los atributos obj.next/previous/parent/firstChild/lastChild. Si quieres ver todas las propiedades disponibles, desde la consola Python , escribe dir(obj).

Si deseas ver una descripción más detallada sobre el navegador de objetos, mientras que el navegador de objetos se encuentre en el objeto en que estés interesado, pulsa NVDA+F1 para lanzar el visualizador del registro. La raíz de todos los objetos de Windows es el escritorio, objeto shell.

Foco vs. navegador de objetos

En tu complemento, podrías querer trabajar con varios objetos y manipularlos. Esto puede incluír cambiar el objeto enfocado, sincronizar el navegador de objetos y el foco, cambiar la función de un objeto y así sucesivamente.

Un objeto en el foco es el control enfocado actualmente. Este está relacionado con el foco del teclado- es decir, sigue al control resaltado. En contraste, un navegador de objetos es el objeto de tu interés. Dado que el navegador de objetos se puede mover en cualquier lugar, puedes examinar dos objetos a la vez: el objeto enfocado y el navegador de objetos. Por ejemplo, podrías enfocar sobre un campo de edición mientras examinas la barra de título con el navegador de objetos. Ya hemos visto un ejemplo más arriba donde podemos comprobar si estamos en dos aplicaciones diferentes mirando los módulos de aplicación del navegador de objetos y del objeto con el foco.

En tu complemento, para obtener el objeto con el foco, escribe someObj = api.getFocusObject(). el someObj puede ser llamado de forma diferente- la convención es utilizar el nombre “obj”. Para obtener el navegador de objetos (que podría ser diferente del del objeto enfocado), utiliza obj = api.getNavigatorObject().

Otras golosinas útiles relacionadas con objetos

Aquí van algunos otros métodos que funcionan con objetos de NVDA, todos ubicados en el módulo api.py:

Si deseas obtener el objeto en primer plano (útil si se desea ver algún objeto secundario de la ventana en primer plano), utiliza obj = api.getForegroundObject().
Desde la consola Python, para ver el número de objetos secundarios que contiene un objeto (por ejemplo, el hijo, o los widgets de una ventana en primer plano), teclea obj.childCount. El valor0 significa que no hay más objetos secundarios.
Para definir un objeto como el foco nuevo o el navegador de objetos, utiliza api.setFocusObject(obj) o api.setNavigatorObject(obj). Esto no cambia la forma que tiene Windows de ver el objeto enfocado, simplemente hace creer a NVDA que el nuevo objeto es el que tiene el foco o el navegador de objetos.
* Puedes obtener varias propiedades de un objeto especificando obj.property donde property es el atributo que deseas ver (por ejemplo obj.value). Entre las propiedades más comunes se incluyen name, value, states, role, appModule, windowClassName, etc.

Ejemplo 1: encontrar el valor de un deslizador en un programa

Supongamos que un usuario te pide que le des el valor de un deslizador en un programa usando un app module. Después de buscar en la jerarquía de objetos y otras propiedades, sabes que la barra de herramientas es el último hijo del objeto en primer plano.

Aquí está el código para implementar esta función:

# Ejemplo de objeto 1

import api
import appModuleHandler

class AppModule(appModuleHandler.AppModule):

    sliderChildIndex = -1 # La variable para almacenar el índice del hijo.

    def getSliderValue(self):
        fg = api.getForegroundObject()
        sliderVal = fg.children[self.sliderChildIndex].value
        return sliderVal

En este código, el método fg.children[index] se utiliza para recuperar al hijo con el índice dado (aquí, ya dijimos que la barra de herramientas es el último hijo, el índice sería menos 1, o el último hijo; podríamos haber utilizado fg.lastChild). Alternativamente, puedes utilizar `fg.getChild (-1) en ciertas situaciones (IAccesible, por ejemplo).

Sin embargo, este código tiene un problema: ¿y si el valor del deslizador está en realidad dentro del primer elemento secundario del control deslizador real? Una forma de solucionar este problema es comprobar el rol del objeto. El código modificado quedaría así:

def getSliderValue(self):
    from controltypes import ROLE_SLIDER # es posible importar desde dentro de un método.
    fg = api.getForegroundObject()
    slider = fg.lastChild
    if slider.role == ROLE_SLIDER: return slider.firstChild.value

Así, cuando estemos seguros de que estamos tratando con el control deslizador, el método devuelve el valor del primer hijo del deslizador (Si ese es el caso). Presta atención a los dos signos de igual para la comparación de igualdad, en lugar de sólo uno que es el signo igual para la asignación.

Hay otros ejemplos que puedes probar para familiarizarte con la navegación y manipulación de objetos:

  • Obtener el nombre de un objeto que se encuentre en otro lugar en el programa.
  • Mover el navegador de objetos al objeto en primer plano.
  • Poner el foco en otro programa.
  • Localizar la primera barra de estado en un programa con varias barras de estado.

Para ver ejemplos de la vida real sobre los objetos de NVDA, consulta el código fuente de NVDA o los códigos fuente de diversos complementos de la comunidad.

Objetos Especiales y redefinición de las propiedades de objetos en tiempo de ejecución

A veces, no es suficiente con trabajar con el comportamiento predeterminado de un control. Por ejemplo, algunas partes de un programa pueden necesitar gestos personalizados, o puede que uno tenga que cambiar el rol de una ventana a la de un botón.

NVDA proporciona dos métodos para crear objetos especiales o superpuestos (o clases), cada uno adaptado para diferentes necesidades:

  • event_NVDAObject_init(self, objeto con el que trabajamos): Si deseas sobreescribir ciertos atributos de un control, como su rol o la etiqueta(nombre), puedes utilizar este método para pedirle a NVDA que tome en cuenta tu”entrada” cuando se encuentran los objetos por primera vez (o inicializados). Por ejemplo, si el control tiene el nombre de clase de ventana TForm (visto en muchas aplicaciones Delphi), puedes pedir a NVDA que trate a este control como una ventana estándar asignando obj.role = ROLE_WINDOW (ver diccionario tipos de control para lista de roles disponibles).
  • chooseNVDAObjectOverlayClasses(self, object, lista de clases): Esto permite a NVDA que utilice su propia lógica cuando se trate de ciertos objetos. Por ejemplo, esto es útil si deseas asignar gestos personalizados para determinadas partes de un programa en tu módulo de aplicación (De hecho, muchos módulos de aplicación crean objetos para hacer frente a determinadas partes de un programa, luego usan chooseNVDAObjectOverlayClasses para seleccionar el objeto correcto cuando se cumplan ciertas condiciones). Estos objetos personalizados se deben basar en un objeto sólido con el que deseamos trabajar (la mayoría de las veces IAccessible es suficiente, por lo tanto los demás objetos superppuestos heredan de, o son los hijos o clases especializadas de los objetos IAccessible). En ciertas situaciones, puedes deshacerte de una propiedad de un objeto usando este método, por ejemplo diciendo a NVDA que no trate a una barra de progreso como tal, eliminando el comportamiento de barra de progreso del objeto en cuestión.

Ten en cuenta que en el caso del segundo método, la clase(s) con el nombre dado debe estar presente en el fichero, que es/son heredados de un objeto base conocido (en Python, la sintaxis para la herencia es claseHija(claseBase), y es por lo general leída como, “esta clase hija hereda de esta clase base”. Veremos un código como éste más tarde).

Ejemplos de sobreescritura de clases y de modificación de roles

A continuación los ejemplos que ilustran el uso de los dos métodos de modificación de sobreescritura y de atributos que hemos comentado anteriormente:

Un ejemplo del primer caso: la modificación de un atributo.

# Reasignar algunos formularios Delphi como ventana.
from controlTypes import ROLE_WINDOW
def event_NVDAObject_init(self, obj):
    if obj.windowClassName == "TForm": obj.role = ROLE_WINDOW

Esto significa que cada vez que nos encontremos con una ventana con la clase llamada “TForm”, NVDA la tratará como una ventana normal.

El ejemplo 2 trata de un módulo de aplicación que tiene dos objetos para tratar con partes específicas de un programa, luego usa chooseNVDAObjectOverlayClasses para asignar la lógica para cada control.

#Un ejemplo de superposición de clases

class enhancedEdit(IAccessible):
    # Algún código para ejecutarse cuando el nombre de la clase de la ventana es MyEdit.

class MainWindow(IAccessible):
    # Otro código, esta vez añadiendo gestos personalizados para la ventana principal del programa.

# En el módulo de aplicación:

def chooseNVDAObjectOverlayClasses(self, obj, clsList):
    if obj.windowClassName == "myEdit": clsList.insert(0, enhancedEdit)
    elif obj.windowClassName == "TWindow": clsList.insert(0, mainWindow)

En ambos casos, el objeto que se desea comprobar debe insertarse como el primer elemento de la clsList. El efecto es que estos objetos personalizados tendrán prioridad cuando se estén buscando gestos o código (comportamiento) para el objeto, y en la información del desarrollador, estos objetos personalizados vendrán por primera vez cuando el MRO (orden de Métodos de Resolución) muestre el navegador de objetos.

Nota: es posible que tengas que afinar estos dos métodos para proporcionar clases de superposición correctas para controles muy específicos (tales como comprobación de nombres, roles específicos, etc.); de lo contrario, es posible que descubras que se asignan dos o más controles de apariencia idéntica a tu objeto personalizado cuando en realidad son muy diferentes. Además, el event_NVDAObject_init sólo está disponible en módulos de aplicación.

Entrada y salida: scripts y mensajes IU

Otro componente crucial de los complementos es manejar órdenes del usuario y mostrar qué está haciendo el complemento. Esto se realiza a través de scripts (en la entrada) y mensajes IU (en la salida).

Un script es un método que se ejecuta cuando el usuario lleva a cabo ciertas órdenes. Por ejemplo, cuando pulsas NVDA+T, NVDA ejecuta un script en el módulo de órdenes globales llamado SayTitle. En Poedit, por ejemplo, cuando un traductor pulsa Control+Shift+A, NVDA leerá los comentarios para el traductor añadidos por el programador para ayudar a clarificar una cadena traducible dada. Esta orden no es una orden nativa de NVDA, pero se definió en el módulo de aplicación de Poedit para llevar a cabo esta función.

Normalmente, un complemento que acepte scripts tendrá un mapa de lista orden:función en algún lugar en el módulo. El más simple es un diccionario de Gestos (órdenes), un diccionario python (llamado normalmente __gestures) que posee órdenes como teclas y scripts como valores para estas teclas (más de una tecla, u orden que puede vincularse a los scripts). Estos diccionarios se cargan cuando el complemento se carga y se borran cuando se sale de NVDA o cuando la aplicación para la que es el módulo de aplicación pierde el foco(es decir, el usuario ha cambiado a otro programa).

Otro modo de enlazar scripts es a través de inserción en tiempo de ejecución. Esto se hace creando otro diccionario de gestos diferente del diccionario gestures que posea gestos sensibles al contexto tales como la manipulación de un sólo control. Entonces el desarrollador podría utilizar inputCore.bindGesture (o inputCore.bindGestures si se ha definido más de un gesto/script) para definir ciertos gestos a la vez, entonces utilizar inputCore.clearGestures luego inputCore.bindGestures(gestures) para eliminar los gestos añadidos. Un modo más elegante, que consiste en scripts para objetos específicos, se tratará cuando hablemos sobre módulos de aplicación y cómo asignar gestos a partes específicas de un programa.

Para la mayoría de los scripts, no tienes que preocuparte por enviar el comando a la aplicación. Sin embargo, en caso de que el script realice tareas adicionales mientras envía la tecla a la aplicación activa, puedes utilizar gesture.send() para enviar el comando primero antes de realizar trabajo adicional.

De manera similar a los scripts, el módulo UI permite verbalizar o braillificar lo que tu complemento está haciendo. Esto se hace usando el mensaje ui.message(algo que decir) donde algo que decir se reemplaza por una cadena para que NVDA la diga. Alternativamente, puedes llamar a los métodos de manejo del habla y del braille directamente si deseas que el habla diga una cosa y la pantalla braille muestre otra. No repasaremos `ui.message’ aquí (verás ejemplos de esos), pero lo más importante son los scripts, así que nos enfocaremos en eso en esta sección.

En el momento de escritura de esta guía, NVDA soporta entrada desde el teclado, pantallas braille con o sin teclado braille y pantallas táctiles. Estos tipos de entrada tienen un prefijo de gesto correspondiente (kb para teclado, br para braille y ts para pantalla táctil) que identifica el tipo de gesto. La salida puede enviarse vía voz y/o braille.

Ejemplo 2: Un diccionario de scripts básico y un mensaje de salida

En este ejemplo, definiremos dos scripts llamados “sayHello” y “sayGoodBye”, luego los vincularemos a dos gestos separados.

# Un fragmento de ejemplo de asignación de un script desde una extensión global.
import ui

def script_sayHello(self, gesture):
    ui.message("Hello!")

def script_sayGoodBye(self, gesture):
    ui.message("Good Bye!")

__gestures={
    "kb:control+NVDA+1":"sayHello",
    "kb:Control+NVDA+2":"sayGoodBye"
}

Ahora cuando pulses Control+NVDA+1, NVDA dirá, “Hello”, y cuando pulses Control+NVDA+2, NVDA dirá, “Good bye.” Este es el código básico al recibir comandos y enviar mensajes.

Ejemplo 3: Scripts para objetos específicos

Al igual que en los objetos especializados anteriores, los scripts se pueden asignar a ciertos objetos especificando el diccionario de gestos para este objeto en particular. Aquí hay un ejemplo de un módulo de aplicación que define scripts para la ventana principal de un programa reproductor multimedia:

# Scripts para objetos para un programa.
from NVDAObjects.IAccessible import IAccessible

class Player(IAccessible):
    def script_saySongName(self, gesture):
        ui.message(self.songTitle_) #Supongamos que se haya definido esa variable.

    __gestures={
        "kb:NVDA+T":"saySongTitle"
    }

# Y en el módulo de aplicación principal:
def chooseNVDAObjectOverlayClasses(self, obj, clsList):
    if obj.windowClassName == "PlayerWindow": clsList.insert(0, Player)

Algo extraño ocurre con este ejemplo: normalmente, cuando se pulsa NVDA+T, NVDA dice el título de la ventana actual, pero en este ejemplo, anuncia el nombre de la canción. Este es el resultado de la búsqueda del script (ver abajo) donde el script para el objeto actual se ejecuta en lugar del script de título de comandos globales. Esta es una forma común de vincular nuevos scripts en tiempo de ejecución.

Orden de búsqueda de scripts y conflictos de órdenes

Según escribas tus complementos con scripts, necesitas recordar el siguiente orden de búsqueda de script cuando intentes asignar órdenes a scripts:

  1. Extensiones globales.
  2. Módulos de aplicación para el programa actualmente enfocado.
  3. Objetos de NVDA con los que estemos tratando.
  4. Órdenes globales.

Por ejemplo, si asignas la orden NVDA+Shift+Y a un script de módulo de aplicación, NVDA ejecutará ese script desde ese programa ya que ninguna extensión global está usando esta orden. Sin embargo, si se instala una extensión global que use esa orden, el script de la extensión global se ejecutará en lugar del script del módulo de aplicación. Del mismo modo, desde el ejemplo anterior, cuando se utilicen programas distintos a ese reproductor multimedia, NVDA ejecutará una orden desde la colección de órdenes globales cuando se pulse NVDA+T; pero mientras utilicemos este reproductor multimedia, NVDA+T anunciará el nombre de la canción (se da prioridad a los objetos de NVDA en los módulos de aplicación).

Debido a la regla anterior, se debe tener cuidado al definir un script para un complemento. Para ayudarte con esto, mantén las siguientes directrices a mano:

  1. En primer lugar, consulta la referencia rápida de órdenes de NVDA para ver si la orden que deseas utilizar se ha definido en las órdenes globales. Deberías tratar de minimizar los conflictos con las órdenes de NVDA incorporadas. Una excepción son las órdenes para los módulos de aplicación, donde una misma orden puede ser utilizada de forma diferente de un programa a otro.
  2. Lee la documentación de los complementos (especialmente las extensiones globales) para ver si algún complemento está utilizando esta orden y, en caso afirmativo, ponte en contacto con el autor del complemento para obtener un vínculo alternativo.

Otros comentarios sobre scripts

  • Puedes utilizar cualquier modificador como parte de las órdenes para scripts (por ejemplo, Alt+NVDA+letra). Sin embargo, para evitar conflictos de órdenes, intenta reducir al mínimo el uso de órdenes que los programas puedan utilizar como Control+letra, Alt+Shift+letra, etcétera.
  • Al asignar órdenes de teclado, las etiquetas de las teclas del teclado no distinguen entre mayúsculas y minúsculas.
  • Puedes definir una categoría de script para mostrar al usuario dónde se utilizará su script adicional (mostrado en el cuadro de diálogo Gestos de entrada en NVDA 2013.3 o posterior). Hay dos maneras de hacerlo: a nivel de módulo mediante el atributo scriptCategory del módulo adicional, o bien designando la categoría para cada script mediante el atributo script_name.category. Se recomienda nombrar la categoría de script del mismo modo que el nombre del complemento.
  • Puedes definir el mensaje del modo de ayuda de entrada para un script utilizando el atributo __doc__ (comúnmente conocido como docstrings). El atributo doc también se utiliza en el diálogo de Gestos de entrada para mostrar la descripción de un script.
  • Si necesitas dejar uno o más scripts sin asignar (por ejemplo, si un gesto entra en conflicto con una orden global), no incluyas el vínculo del gesto para el script en el diccionario de gestos. Esto ayuda a minimizar los conflictos de gestos y permite a los usuarios asignar gestos personalizados para los scripts.
  • Si hay dos objetos, A y B, y si B hereda de A y ambos contienen la misma orden para un script, puedes asignar “None” al nombre del script en el objeto B (subclase) para evitar una orden cuando se trate de órdenes del objeto B. Por ejemplo, si F10 está definido para ambos objetos y F10 no se utiliza en el objeto B, puedes asignar el comando F10 del objeto B a”None” para que F10 pueda enviarse al sistema operativo. Esto se implementa en algunos módulos del núcleo de NVDA y en el complemento StationPlaylist Studio.

Eventos

Puedes pedirle a NVDA que haga algo si ocurre algo. Por ejemplo, puedes pedirle a NVDA que diga el nuevo nombre de un objeto cuando cambie su nombre, o decir el valor del nuevo elemento cuando se enfoque. Estas condiciones o acciones se denominan eventos.

Cuando se produce un evento, NVDA hace lo siguiente:

  1. Encuentra qué fue el evento (por ejemplo, una casilla de verificación obtiene el foco).
  2. Realiza acciones para el evento (por ejemplo, indica el nombre y el estado marcado de esta casilla de verificación).
  3. Pasa el evento por la cadena en caso de que otros objetos puedan tener acciones asociadas con el evento.

Dependiendo de dónde se defina el evento, necesitarás dos o cuatro cosas al definirlo. Si se declara desde el módulo de un complemento, las partes requeridas son el nombre del evento, el módulo en cuestión (self), el objeto y el siguiente manejador en caso de que el objeto tenga otros eventos asociados. Si se define como parte de un objeto, se requiere el nombre del evento y el objeto (self).

Una rutina típica de eventos se ve así:

def event_eventName(self, obj, nextHandler):
    # Hace alguna acción.
    nextHandler()

Para eventos de objeto, usa:

def event_eventName(self):
    # Rutina de evento.

De hecho, hemos conocido un”evento” real antes: event_NVDAObject-Init. Se trata de un evento especial (uno de los muchos eventos definidos en NVDA) disparado cuando NVDA se encuentra con un nuevo objeto y lo inicializa de acuerdo con su entrada (consulta la sección sobre sobreescritura de propiedades de un objeto para obtener más información). Veamos otros eventos que puedes ver mientras escribes tu complemento.

Ejemplo 4: Anunciar el nombre cambiado de un control

El siguiente código procede de uno de los complementos de módulos de aplicación.

A continuación se muestra una rutina para un evento que le indica el nombre de algún texto en la pantalla cuando el texto cambie.

def event_nameChange(self, obj, nextHandler):
    if obj.windowClassName == "TStaticText": ui.message(obj.name)
    nextHandler()

Como puedes ver, siempre que el nombre del objeto de texto cambie, NVDA anunciará el nuevo nombre al usuario. El evento”cambio de nombre” es uno de los muchos eventos para los que puedes definir acciones personalizadas en tu complemento (la lista completa va a continuación).

Nota: puedes definir eventos para cualquier objeto de tu elección, especialmente controles en un programa (donde puedes definir acciones personalizadas para eventos en tu módulo de aplicación). Si este es el caso, debes asegurarte de que el control cumpla ciertas condiciones establecidas, como el nombre, la función, etc., para permitir que NVDA mantenga un”ojo” en ese objeto específico.

Lista de posibles eventos

Esta es una lista de eventos comunes para los que puedes definir acciones personalizadas en tu complemento:

  • gainFocus: el usuario ha movido el foco a un control específico, o el usuario acaba de cambiar a un programa.
  • loseFocus: el contrario a gainFocus.
  • nameChange: el nombre de un control ha cambiado (mira arriba para ver un ejemplo).
  • valueChange: El valor del control, como por ejemplo el texto de un campo de texto, ha cambiado.
  • stateChange: Útil para realizar un seguimiento de si las casillas de verificación, los botones y el estado de otros controles (marcados, seleccionados, etc.) han cambiado.
  • Foreground: el objeto que nos interesa se ha convertido en la ventana de primer plano del programa.

Los eventos menos comunes que se utilizan en situaciones específicas incluyen:

  • typedCharacter: el usuario ha introducido algo en un teclado.
  • appModule_gainFocus: el usuario ha cambiado a la aplicación donde se define un módulo de aplicación. Los usos comunes incluyen añadir órdenes de pantalla táctil para aplicaciones específicas, anunciar información adicional sobre el estado actual de la aplicación y así sucesivamente.
  • appModule_loseFocus: el contrario a appModule_gainFocus.
  • descriptionChange: la descripción de un control ofrecida por la API de accesibilidad ha cambiado.
  • suggestionsOpened: se utiliza en los controles donde se puede escribir algo y las sugerencias se mostrarán en base al texto introducido. La implementación predeterminada en NVDA reproduce un sonido para indicar la aparición de sugerencias.
  • suggestionsClosed: el contrario a suggestionsOpened. Los eventos de sugerencias requieren NVDA 2017.3 y el objeto debe heredar de la clase NVDAObjects.behaviors.editableTextWithSuggestions.

Eventos dentro de objetos

La sección anterior describía las rutinas de eventos desde la perspectiva de un complemento. Esta es sólo una manera de definir los eventos. La otra manera es definir eventos desde dentro de los objetos, y es la misma que la anterior excepto que sólo toma un argumento (self).

Otros componentes

Además de objetos, scripts y eventos, puedes añadir otros componentes en tu complemento para trabajar con controles específicos. Por ejemplo, puedes utilizar un módulo textInfo (como NVDAObjects.NVDAObjectTextInfo) para trabajar con offsets de texto y texto en campos de edición y otros controles, o utilizar módulos externos de desarrolladores externos para tareas especializadas como el acceso al registro de Windows (_winreg) y otras. También puedes utilizar los módulos integrados de Python (time, functools, etc.) para operaciones avanzadas.

Un componente notable es text infos, una forma de permitir que los complementos tengan acceso al texto ubicado en los objetos. Puedes acceder al texto, desplazarte por él (por ejemplo, mediante líneas y palabras) y manipular partes mediante intervalos de marcación y desplazamientos. Para la mayoría de los complementos, no es necesario definir un text info personalizado, ya que la API de accesibilidad subyacente proporcionará la información adecuada.

Otro componente útil es la biblioteca de presentación de texto matemático (mathPres). Esto se utiliza para permitir que NVDA acceda al contenido matemático en lugares como navegadores web, así como para que los complementos definan capas personalizadas de presentación matemática y formas de acceder al contenido matemático en varias aplicaciones. Hasta ahora, la recuperación de contenido matemático se hace en texto marcado en MathML con MathPlayer instalado.

Si deseas almacenar los ajustes para tu complemento, utiliza ConfigObj o el gestor de configuración integrado de NVDA para almacenar los archivos de configuración y los ajustes. ConfigObj define los ajustes como una colección de diccionarios que se pueden actualizar en tiempo real. También puedes pasar un mapa de validación para permitir al gestor de configuración (config.conf) de NVDA validar los ajustes para tu complemento y dejar que los ajustes adicionales se conviertan en ajustes específicos del perfil.

Finalmente, puedes pedirle a NVDA que realice algunas rutinas mientras el complemento se esté cargando o finalizando. Esto se hace definiendo el método __init__ y terminate para el complemento. Dependiendo del tipo de extensión, utiliza:

  • Para extensiones globales:
    def init(self):
    super(GlobalPlugin, self).init()
    # La rutina a hacer cuando la extensión global se cargue.
    # ¡Precaución! siempre deberías llamar al método super primero para inicializar la clase padre correctamente.
  • Para módulos de aplicación:
    def init(self, *args, kwargs):
    super(AppModule, self).__init__(*args,
    kwargs)
    # Lo que debería hacer NVDA cuando el app module se cargue.
  • Para terminar, independientemente del tipo de complemento:
    def terminate(self):
    # Hacer algo cuando el complemento termine.
    # ¡Precaución! nunca inicializes cualquier módulo del núcleo tal como GUI en el método terminate, ya que al hacerlo evitarás que NVDA salga correctamente.

Construyamos un complemento

Ahora tenemos una visión general básica de los componentes de los complementos, estamos listos para crear algunos complementos sencillos. Pero primero, repasemos el proceso real de desarrollo de complementos, consejos de depuración, lo que se debe hacer y lo que no se debe hacer y otras cosas.

Consejos para planificación y desarrollo de complementos

A lo largo de los años, la comunidad de NVDA ha creado una serie de potentes complementos para los usuarios. Durante estos años, los redactores de complementos recopilaron algunos consejos útiles cuando se trata de escribir sus propios complementos. He aquí algunos de ellos:

  • Conocer a NVDA: es importante que te familiarices con las órdenes, conceptos y consejos de NVDA. Suscríbete a los grupos de usuarios de NVDA para obtener más información sobre NVDA y conocer cómo funciona, ya que lo ampliarás a través de tus complementos.
  • Conocer el producto que tienes a mano: como se mencionó anteriormente, es importante que conozcas el software para el que estás escribiendo el módulo de aplicación, los sintetizadores y las pantallas braille para los que vas a escribir el controlador, etcétera.
  • Planificar con anticipación: si sabes que mantendrás tu complemento durante varios meses o años, es útil tener un plan y escribir el código del complemento para prepararte para futuras extensiones. Por ejemplo, trabajando en las características que necesitas implementar ahora, dividiendo partes de un programa en objetos y así sucesivamente.
  • Listo para depurar y probar tu complemento: escribir tu código de complemento es sólo una parte del desarrollo global del complemento. La otra parte es probar y depurar tu complemento para asegurarte de que los usuarios lo utilizan con errores mínimos. A medida que escribas tus complementos, asegúrate de probar tu código con regularidad.
  • Lo más importante, diviértete.

Qué hacer y qué no

Éstas son algunas cosas que deberías hacer y no hacer durante el desarrollo de un complemento:

  1. Habla con los usuarios: es importante recordar que tus complementos serán utilizados por los usuarios de NVDA de todo el mundo, por lo que es importante mantenerte en contacto con ellos para recopilar informes de errores y sugerencias.
  2. Pide ayuda si es necesario: Si estás atascado, puedes pedir ayuda a otros desarrolladores de complementos en cualquier momento para obtener soluciones o consejos, o si lo necesitas, solicita la colaboración de otros desarrolladores de complementos.
  3. Prueba tu complemento en más de un equipo: a veces, un error en un equipo puede ayudarte a resolver problemas en tu complemento en el equipo más adelante.
  4. No utilices código imaginativo sin entender tus intenciones: un error tipográfico o una indentación olvidada puede convertirse en un problema cuando depuras un complemento.
  5. Mantente al día con los cambios básicos de NVDA: a veces, puede que descubras que tu complemento no funcione debido a los cambios en el código del núcleo de NVDA. Asegúrate de leer la sección “Cambios para desarrolladores” en el documento Novedades de NVDA para mantenerte al día con los cambios de código que puedan afectar a tu complemento.

Preguntas frecuentes sobre componentes de complementos y desarrollo

P. Cuando trato de obtener un objeto usando un índice, éste obtiene uno después del índice que escribí.
Este es el efecto colateral de la indexación basada en cero (el recuento comienza en 0).

P. Al importar un módulo, NVDA dice que no puede localizar el módulo.
¿Escribiste el nombre correcto del módulo? ¿Extrajiste los archivos del módulo en la ubicación correcta? Intenta corregir el error tipográfico, observa la ruta de importación y vuelve a intentar importar.

P. ¿Cuál es la diferencia entre la revisión simple y la revisión normal y cuál debo usar?
La revisión simple excluye los objetos de diseño como ventanas, agrupaciones, etc. que se colocan para propósitos de diseño. La revisión normal también incluye esto. La elección de usar la revisión simple versus la revisión normal depende de tu situación.

P. La orden para mi app module no funciona en mi app module, sino que NVDA hace otra cosa.
Comprueba si está instalada una extensión global que utiliza la orden. Primero, quita la extensión global e inténtalo de nuevo.

P. ¿Cómo puedo utilizar Win32 API en mi complemento u objeto?
Existe un documento escrito por un desarrollador de complementos que habla sobre el uso de Win32 API en su complemento. Selecciona este enlace para ver este documento.

P. ¿Cómo puedo crear diálogos en mi complemento?
Necesitas importar dos módulos: GUI (import gui) y WXPython (import wx).

P. ¿Puedo crear funciones y asignar variables fuera de las clases de módulo?
Sí. Esto es útil si necesitas hacer referencia a ellos desde dentro de la clase del complemento. Por ejemplo, es posible que tengas una función definida fuera de tu clase que necesitarás utilizar desde más de un método en una clase de extensión global.

P. Quiero guardar la configuración de usuario para mi complemento. ¿Se puede hacer esto?
Sí. Deberás utilizar la biblioteca ConfigObj(configObj) para administrar la configuración. Algunos complementos (como OCR) que utilizan archivos de configuración almacenan su configuración como un archivo ini en la carpeta de configuración de usuario de NVDA. En el caso de las extensiones globales, puedes cargar y guardar la configuración de usuario desde el complemento cuando se crea el complemento (init) o se finaliza (terminate), respectivamente. Esto no se puede hacer fácilmente con los módulos de aplicación. Además, tendrás que proporcionar una alternativa (órdenes, diálogos, etc.) en la que los usuarios puedan configurar opciones adicionales.

P. Tengo un script que llama a una función que se ejecuta durante mucho tiempo, y no puedo ejecutar órdenes de NVDA cuando se ejecuta mi script.
Una forma de solucionar esto es usando hilos (operaciones separadas e independientes en un programa) a través del módulo de hilos de Python. Para ello, crea un método que sepas que se ejecutará durante mucho tiempo y, a partir del script que llama a este método, crea un nuevo hilo (ver la documentación del módulo de hilos de Python) que se encargará de ejecutarlo. De esta forma, se pueden ejecutar otras órdenes de NVDA mientras el método adicional realiza su trabajo (consulta el módulo de reconocimiento de voz de Google para obtener un código de ejemplo).

P. Me gustaría conectar un módulo escrito en la sintaxis de Python 3 para utilizarlo como un complemento de NVDA.
Esto no se puede hacer fácilmente. Un módulo práctico para este propósito es six, que permite ejecutar el código Python 2 y 3. NVDA usa Python 2 porque WXPython utiliza Python 2, y hasta que WXPython no sea reescrito para soportar Python 3, no se puede ejecutar el código Python 3 en NVDA.

No incluimos preguntas frecuentes de programación relacionadas con Python, ya que hay sitios que responden a preguntas sobre Python, tales como las relacionadas con el estilo de codificación. Consulta estos documentos si tienes problemas con el código Python.

Ahora que hemos cubierto los componentes básicos de un complemento, vamos a aprender acerca de cómo empaquetar lo que sabes en tus propios módulos de complemento: extensiones globales, módulos de aplicación y controladores.

Introducción a las extensiones globales

Una extensión global añade características disponibles en todas partes. Por ejemplo, si hay un control que se utilizará en muchas aplicaciones, puedes escribir una extensión global para manejarlas en NVDA. Otro ejemplo es la adición de funciones adicionales a NVDA que se puedan utilizar en todos los programas, como la capacidad de OCR, la gestión de marcadores de ubicación, etc.

Una extensión global es un archivo de código fuente de Python (.py) con el nombre de tu plugin. Por ejemplo, si estás añadiendo soporte para campos de edición enriquecidos en muchas aplicaciones, puedes nombrar la extensión como richEditSupport.py. Cuando los nombres, trata de ser breve para que puedas ver lo que hace tu extensión.

Plan de desarrollo típico para extensiones globales

Normalmente, una extensión global se desarrolla así:

  1. Tú o alguien sugiere una característica o soporte para un control en particular a través de diferentes programas.
  2. Planificas tu extensión global (consulta la sección sobre cuándo escribir o no escribir extensiones globales).
  3. escribes tu extensión global y la pruebas. Una vez hecha y probada, liberas la extensión.

Dado que las extensiones globales son archivos Python, puedes utilizar toda la potencia de python en el código de tu complemento. Además, dado que las extensiones globales tienen acceso a toda la potencia del código NVDA, como eventos, scripts y objetos, puedes utilizar los conceptos aprendidos en las secciones anteriores.

El código de la extensión global

Como se ha mostrado anteriormente, el procedimiento para escribir extensiones globales es el mismo que para escribir cualquier programa Python, excepto que importas globalPluginHandler y colocas tu código de complemento en una clase llamada GlobalPlugin que hereda de globalPluginHandler.GlobalPlugin (consulta el ejemplo en el capítulo introductorio). Si necesitas utilizar módulos de terceros, debes colocar el paquete en la misma carpeta que el archivo de extensión global e importar los módulos externos. A continuación, define los objetos (normalmente objetos de superposición), métodos, etc. en tu código.

Cuándo escribir o no escribir extensiones globales

Dado que las extensiones globales se utilizan en todas partes, es posible que tengas la tentación de escribir soporte para una sola aplicación utilizando solamente una extensión global. Sin embargo, este no es el caso. Existen otras pautas a tener en cuenta a la hora de decidir si escribir una extensión global o no:

Podrías considerar la posibilidad de escribir una extensión global si:

  1. Tú o un usuario deseais utilizar una cierta característica en todas partes.
  2. Necesitas soportar los mismos controles en diferentes aplicaciones, siempre que el control se comporte igual en estos programas.

No deberías escribir una extensión global si:

  1. Si deseas mejorar el soporte para una sola aplicación.
  2. Estás escribiendo soporte para sintetizadores de voz o pantallas braille.

Algunas cosas más que recordar sobre las extensiones globales

  • Cuando escribes scripts en tu extensión global, las órdenes que les asignes tendrán prioridad (buscadas primero). Por lo tanto, es importante consultar la guía del usuario de NVDA y la ayuda de otros complementos para minimizar los conflictos de órdenes.
  • Cada extensión global debe estar ubicado en el directorio globalPlugins en la estructura de carpetas del complemento.
  • Es posible usar más de un archivo Python en tu extensión global. Si este es el caso, necesitas ponerlos en una carpeta (el nombre debe ser el nombre de la extensión) dentro de la carpeta globalPlugins, con el archivo principal de la extensión llamado init.py.
  • Si necesitas hacer algo cuando la extensión global esté cargada (como por ejemplo, cargar la configuración de usuario), debes escribir un método init en tu clase de extensión. En este método, debes llamar primero al método init en super (globalPluginHandler.GlobalPlugin) antes de hacer otro trabajo de inicialización. Además, si necesitas hacer algo cuando la extensión global termine, define el método terminate.

Repasemos algunos ejemplos y ejercicios.

Ejemplo 1: Escribir braille computerizado utilizando el teclado QWERTY

Te vas a reunir con un cliente que utiliza el traductor braille de Duxbury (un popular programa de producción de documentos braille). Este cliente está trabajando con otro usuario de NVDA que desea escribir braille desde el teclado de su computadora en cualquier lugar. Basado en esto, decides escribir una extensión global, y encontraste un módulo que permite al teclado del ordenador actuar como un teclado braille usando una función.

La extensión global, llamada brailleWrite.py, se vería así:

# Un ejemplo de extensión global.

import qtbrl # El módulo de entrada braille.
import globalPluginHandler

class GlobalPlugin(globalPluginHandler.GlobalPlugin):
    brlentry = False # La entrada braille no está activa.

    def script_toggleBrailleEntry(self, gesture):
        self.brlentry = True if not self.brlentry else False # alternar modo de entrada Braille.
    script_toggleBrailleEntry.__doc__="Alterna la entrada Braille entre encendida y apagada."
    __gestures={
        "kb:NVDA+X":"toggleBrailleEntry"
    }

Con estos antecedentes en mente, prueba algunos de los ejercicios cortos que se presentan a continuación.

Ejercicios

  1. Escribe una extensión global llamada nvdaVersion.py para decir la versión actual de NVDA cuando se pulse NVDA+Shift+V.
  2. Un usuario quiere oír la hora anunciada cada minuto. Usando el reloj en la bandeja del sistema, escribe una extensión global para anunciar cuándo cambia la hora (pista: es necesario usar un evento y comprobar la función del objeto reloj).

Introdución a los módulos de aplicación

Un módulo de aplicación mejora el soporte para un programa en particular. Por ejemplo, puedes escribir un módulo de aplicación que agregue órdenes de conveniencia para leer varias partes de la pantalla, o puedes definir cómo debe comportarse un control particular en un programa.

Un módulo de aplicación es un archivo Python (.py) con el nombre correspondiente al nombre ejecutable de un programa. Por ejemplo, un módulo de aplicación para Winamp se llama winamp.py ya que el nombre ejecutable de Winamp es winamp.exe.

El mismo NVDA viene con varios app modules, como Winamp, Adobe Reader, programas de Microsoft Office y así sucesivamente.

Diferencias entre módulos de aplicación y extensiones globales

A primera vista, los módulos de aplicación pueden tener el mismo aspecto que cualquier extensión global. Sin embargo, los módulos de aplicación tienen propiedades adicionales de las que carecen las extensiones globales, incluyendo:

  • En lugar de globalPluginHandler, necesitas importar appModuleHandler. La clase a implementar es AppModule(appModuleHandler.AppModule).
  • Los módulos de aplicación se almacenan en la carpeta appModules de la estructura de directorios del complemento y reciben el mismo nombre que el nombre ejecutable del programa.
  • Puedes pedir a NVDA que entre en el modo de suspensión en un programa donde NVDA no hable o no tenga nada en braille mientras estés utilizando el programa, y cualquier orden de teclado que pulses será manejado directamente por el programa. Esto se hace estableciendo el atributo sleepMode en la clase AppModule a True.
  • La rutina event_NVDAObject_init sólo está disponible en los módulos de aplicación.
  • Puedes pedir a NVDA que vigile un objeto para manejar eventos aunque el usuario esté usando otra aplicación.

Proceso y estrategias de desarrollo de módulos de aplicación

Así se desarrolla un módulo de aplicación típico:

  1. Tú o un usuario solicitais soporte mejorado para un programa.
  2. Si es posible, ponte en contacto con el proveedor de la aplicación (programador) para solicitar mejoras de accesibilidad para el programa por su parte.
  3. Con o sin la cooperación del proveedor de aplicaciones, examinarías cómo funciona el programa y las áreas de la pantalla que necesitan ser leídas.
  4. Escribe y prueba el módulo de aplicación (con usuarios) hasta que esté listo para su lanzamiento.

A medida que escribas app modules, prueba estos consejos:

  1. Utiliza objetos para representar partes de un programa. Esto se hace en dos pasos: define el control para las partes de un programa a través de objetos (heredando de algún objeto como IAccessible), luego utiliza la rutina chooseNVDAObjectOverlayClasses para decirle a NVDA que trabaje con tu objeto personalizado cuando trabaje con ese control. Mira la sección de clases de superposición para consejos.
  2. Si es posible, prueba tu app module utilizando dos o más versiones del programa para asegurarte de que tu módulo de aplicación funciona con esas versiones.
  3. No deberías incorporar todas las características deseadas en la versión 1.0 – deja algunas de ellas para una futura versión.

Ejemplo 2: Módulo de aplicación simple en el Bloc de notas

Supongamos que deseas averiguar qué línea estás editando en el Bloc de notas. Asumiendo que el Bloc de notas mostrará la barra de estado en todo momento, deseas asignar una combinación de teclas para leer el número de línea actual.

El módulo de aplicación para el Bloc de notas se vería así:

# El módulo de aplicación de ejemplo para bloc de notas, notepad.py.
import appModuleHandler
import api
import ui

class AppModule(appModuleHandler.AppModule):
    def script_sayLineNumber(self, gesture):
        # Supongamos que el número de línea sigue el formato "  ln 1".
        lineNumList = api.getStatusBar().name.split()
        lineNum = lineNumLisst[2]+linenumList[3]
        ui.message(lineNum)

    __gestures={
        "kb:NVDA+S":"sayLineNumber"
    }

Por lo tanto, cada vez que ejecutes el Bloc de notas, cuando pulses NVDA+S, NVDA dirá el número de línea.

Ejemplo 3: Silenciar NVDA en Openbook

Openbook es un programa de lectura y escaneo de Freedom scientific. Como Openbook proporciona voz, puedes decir a NVDA que entre en modo latente mientras Openbook (openbook.exe) se ejecute usando el módulo de aplicación siguiente:

# Silenciar a NVDA en openbook, openbook.py.
import appModuleHandler

class AppModule(appModuleHandler.AppModule):
    sleepMode = True

Con esa única línea de código, NVDA entrará en modo latente en ese programa (sólo debes hacerlo si el programa proporciona soporte de voz y/o braille por sí solo).

Ejemplo 4: Anunciar cambios de propiedad de control mientras se usa otra aplicación

Puedes pedir a NVDA que gestione eventos específicos mientras se concentra en otra aplicación. Esto se hace llamando a eventHandler.requestEvents en el método init del módulo de aplicación. Para poder invocar esto, necesitas el ID de proceso (PID) para la aplicación, el nombre de clase de ventana para el objeto y el nombre del evento a tratar.

El siguiente código permite a NVDA anunciar los cambios de valor mientras se centra en otra aplicación.

# Ejemplo de módulo de aplicación para un programa de mensajería.
# El objeto que deseamos rastrear tiene el nombre de la clase de ventana "MessengerWindow".

import appModuleHandler
import eventHandler

class AppModule(appModuleHandler.AppModule):
    def __init__(self, *args, **kwargs):
        super(AppModule, self).__init__(*args, **kwards)
        eventHandler.requestEvents(self.processID, "MessengerWindow", "valueChange")

Una vez definidos, aunque estén enfocados en otra aplicación, se anunciarán nuevos mensajes (valores).

Propiedades y métodos útiles de los módulos de aplicación

sleepMode y processID son sólo dos de los muchos atributos que tienen los módulos de aplicación. Otras propiedades y métodos útiles utilizados en los módulos de aplicación incluyen los siguientes:

  • appName: el nombre de la aplicación (normalmente el nombre del ejecutable).
  • productName: Registra el nombre real del producto para la aplicación.
  • productVersion: Registra la versión de la aplicación.
  • is64BitProcess: si es true, la aplicación es un proceso de 64 bits (sólo true si se está usando una aplicación de 64 bits en versiones Windows de 64 bits).
  • dumpOnCrash: si estás depurando aplicaciones que se bloquean con frecuencia, puedes llamar a esta función para permitir que NVDA guarde un volcado de esta aplicación en el directorio de archivos temporales para que puedas recuperarlo más tarde.

Y otras propiedades. Escribe dir(obj.appModule) desde la consola Python para obtener la lista completa.

Otros comentarios sobre los módulos de aplicación

Aquí hay otras observaciones sobre los módulos de aplicación:

  • Si encuentras que las diferentes versiones del programa están dispuestas de forma diferente, por ejemplo, las ubicaciones para los controles son diferentes, entonces puedes escribir código que pueda manejar estos casos. Hay una serie de opciones entre las que puedes elegir: añadir algunas constantes en tu módulo de aplicación para manejar diferentes ubicaciones de objetos, escribir código para estos controles (uno por versión) en objetos personalizados que se seleccionarán en el método de clases de superposición, etc.
  • Si es posible, intenta trabajar con los servicios que proporciona la aplicación, como los métodos COM (Component Object Model) (por ejemplo, el módulo de aplicación de Outlook), API’s que proporciona la aplicación (como Winamp) y así sucesivamente.
  • Para soportar una aplicación que funcione igual que otro programa (especialmente si estás escribiendo un módulo de aplicación para una versión de 64 bits de un programa de 32 bits para el que has escrito un módulo de aplicación), utiliza el siguiente fragmento de código (llamado aliasing):
    from appName import *
    donde appName es el nombre del app module y * (asterisco o estrella) significa importarlo todo. Para un ejemplo de esto, mira los módulos de aplicación de NVDA para Miranda32 y Miranda64.
  • Si deseas ampliar un app module que venga con NVDA, utiliza el siguiente fragmento de código (llamado sobreescritura del módulo incorporado):
    from nvdaBuiltin.appModules.appName import *
    Donde appName es el módulo de aplicación que deseas ampliar. Por ejemplo, si deseas admitir diferentes controles en la calculadora de Windows (calc.py), utiliza:
    from nvdaBuiltin.appModules.calc import *
  • Muchos módulos de aplicación (tanto integrados como de terceros) utilizan nombres de applicación como parte del nombre de una constante (un valor que no cambia). Por ejemplo, en el módulo Powerpoint de NVDA (powerpnt.py), muchas constantes comienzan con “PP”. Del mismo modo, en el app module de Station Playlist Studio, muchas constantes en el archivo del módulo de aplicación (splstudio.py) comienzan con “SPL”. Esto se usa para recordarte dónde se utilizan estas constantes.

Controladores

Un controlador permite que un software como NVDA se comunique con el hardware o utilice la funcionalidad proporcionada por otro software. Normalmente, cuando la gente habla de controladores, usualmente se refiere a un programa instalado en una computadora que permite que el software se comunique con un hardware específico, como tarjetas de vídeo, teclados y demás.

En NVDA, los controladores se refieren a módulos que NVDA puede utilizar para comunicarse con un sintetizador de voz o una pantalla braille. Por ejemplo, puedes escribir un controlador de pantalla braille que envíe una salida braille a la pantalla braille, o pedirle a tu sintetizador que cambie de idioma y proporcione opciones configurables.

Componentes del controlador

Todos los controladores (independientemente del dispositivo de destino o software que se admita) importan los módulos apropiados, como “synthDriverHandler”. Para la mayoría de los controladores, la mayoría del código del controlador trata sobre la comunicación con el dispositivo o software de destino, y todos los controladores deben definir la clase de controlador (synthDriverHandler.SynthDriver o braille.BrailleDisplayDriver).

Todas las clases de controladores, como mínimo, deben contener:

  • Identificador del controlador: una cadena de caracteres como “oneCore” que identifique de forma unívoca a un controlador determinado.
  • Nombre amigable: el nombre que aparecerá en los cuadros de diálogo de sintetizador o de configuración braille.
  • Indicador de disponibilidad: un método de clase llamado check que indica a NVDA que el controlador está listo para su uso.
  • Gestor de conexiones: conjunto de rutinas que indican a NVDA cómo localizar un determinado sintetizador o una pantalla braille.
  • Manejador de salida: una función que realiza el procesamiento de salida real. Para los sintetizadores, el método speak debe estar presente; para las pantallas braille, se necesita el método display.

Para los sintetizadores de voz, es necesario tener:

  • Opciones de timbre de configuración del sintetizador: una lista de ajustes de los sintetizadores que los usuarios pueden ajustar mediante el timbre de configuración del sintetizador.

Para las pantallas braille:

  • Manejadores de entrada: si se desea la entrada de la pantalla braille, el autor del controlador debe implementar detectores para órdenes tales como teclas braille, botones de enrutamiento y hardware adicional.
  • conjunto de órdenes: un mapa que identifique las asignaciones de órdenes de NVDA para varios botones de hardware de la pantalla.

Unas pocas cosas importantes que recordar antes, durante y después del desarrollo de controladores

  • Antes de escribir un controlador, asegúrate de tener el software y/o hardware necesarios.
  • Asegúrate de estudiar los protocolos y las API’s utilizadas por un sintetizador de voz o una pantalla braille (esto es más importante para las pantallas braille que pueden implementar diferentes protocolos).
  • Asegúrate de saber cómo comunicarte con el equipo: puertos, IDs USB, direcciones Bluetooth, configuración del puerto serie, etc.
  • Trabaja con otra persona que utilice el equipo o el software para el que estás escribiendo el (los) controlador (es).

Pasos típicos de desarrollo de un controlador

Cuando escribas controladores, es posible que desees seguir los pasos recomendados para el desarrollo de módulos de aplicación (planificación, comunicación con los proveedores, pruebas de usuario, etc.). Sin embargo, dado que los controladores requieren un conocimiento íntimo del hardware y/o del software, deberías dedicar más tiempo a probar tu controlador. Esto es más importante si estás escribiendo un controlador para una pantalla braille que puede enviar órdenes arbitrarias (órdenes braille, botones de enrutamiento, etc.).

Compartiendo tu complemento y experiencia con otros

Una vez que hayas terminado de desarrollar tus complementos, es posible que desees compartir tu código con otros. A lo largo del camino, podrías aportar tu conocimiento para que otros puedan beneficiarse de tus experiencias.

Este capítulo está diseñado para proporcionar orientación sobre la liberación y el mantenimiento de complementos, así como para conectarte con los usuarios de complementos y otros desarrolladores del núcleo y de complementos de NVDA de todo el mundo.

La lista de complementos de NVDA

Si deseas mantenerte en contacto con los usuarios de tu complemento o deseas aprender o contribuir con tu complemento a otros, suscríbete ala lista de complementos de NVDA. Esta es una lista de poco tráfico dedicada a discutir los complementos actuales y futuros, así como a revisar otros complementos creados por miembros de la comunidad o hacer que otros desarrolladores de complementos revisen sus complementos en todo el mundo.

El sitio web y el repositorio de código de los complementos de la comunidad de NVDA

Para descargar u obtener más información sobre los diversos complementos creados por los usuarios de NVDA, visita el sitio web de los complementos de la comunidad de NVDA. Puedes examinar los complementos actualmente disponibles, ver los complementos en desarrollo y leer las directrices de desarrollo de complementos.

Para los desarrolladores que deseen leer el código que impulsa a varios complementos, puedes buscar repositorios de complementos almacenados en GitHub. Los desarrolladores de complementos de la comunidad de NVDA utilizan Git para el control de versiones.

Algunos de los repositorios útiles y educativos son:

  • add-on template: este es el repositorio de código fuente para la plantilla de complementos de la comunidad.
  • Place markers de Noelia Martínez: agrega funcionalidad de marcadores de posición y proporciona un buen ejemplo sobre el uso de text infos.
  • Windows 10 App Essentials de Joseph Lee: proporciona soporte mejorado para Windows 10 y varias aplicaciones universales, considerado un clásico en la forma en que las extensiones globales y módulos de aplicaciones trabajan juntos e incluye ejemplos de clases de superposición y comportamientos de control que se derivan de los objetos UI Automation.
  • Read Feeds de Noelia Martínez: facilita el descubrimiento de feeds en varios sitios web e incluye un ejemplo sencillo de almacenar y validar configuraciones adicionales.
  • NVDA Remote Support de Christopher Toth y Tyler Spivey: un popular complemento utilizado para la solución remota de problemas y soporte técnico, proporciona ejemplos de cómo se utilizan varias bibliotecas externas de Python.
  • StationPlaylist Studio de Joseph Lee: mejora el uso de StationPlaylist Studio, proporciona ejemplos interesantes sobre las clases de superposición y la API de aplicaciones, el uso de hilos y diálogos adicionales y otras interfaces de usuario.

Información miscelánea

Por favor, añade material adicional a esta guía. En el Equipo de Complementos de NVDA agradecemos las contribuciones de otros desarrolladores y usuarios de complementos por todo el mundo.

Apéndices

Apéndice A: Diccionario de términos de complemento

Los siguientes términos se utilizan a lo largo de esta guía de desarrollo, así como en la comunidad de complementos para referirse a complementos, procesos de desarrollo, etcétera.

  • Complemento: una extensión para un programa. En el mundo de NVDA, un complemento se refiere a paquetes adicionales que los usuarios pueden instalar para ampliar la funcionalidad de NVDA, mejorar la compatibilidad con una aplicación o añadir nuevos sintetizadores de voz o pantallas braille.
  • Aplicación: sinónimo de programa.
  • Módulo de aplicación: un módulo que añade o mejora el soporte para un programa.
  • API: interfaz de programación de aplicaciones. En inglés, Application Programming Interface.
  • Clase base: clase padre de un objeto.
  • Pantalla Braille: un hardware o software que emite texto a través de una salida braille táctil y/o permite a los usuarios ingresar texto a través de un teclado braille u otros mecanismos de entrada.
  • Módulo integrado: un módulo que viene con NVDA y que puede ser sobreescrito o ampliado por los complementos opcionalmente.
  • Caret: cursor que se muestra en pantalla, generalmente visto al editar texto o al navegar por documentos.
  • clase: definición de un objeto.
  • Evento: una rutina llamada cuando suceden ciertas cosas, como la introducción de caracteres, cambios en el texto de la pantalla, una casilla de verificación marcada y así sucesivamente.
  • Función: un pedazo de código que realiza algo con uno o más parámetros de entrada y opcionalmente devuelve algo.
  • Gesto: una entrada como pulsaciones de teclas, gestos en la pantalla táctil, teclas braille, etcétera.
  • Extensión global: un módulo que añade características en todas partes.
  • Módulo: conjunto de variables, funciones, clases y otros dentro de un fichero.
  • Objeto: una definición de clase con vida propia.
  • Script: una función que se adjunta (asigna) a un gesto.
  • Sintetizador de voz: un software o hardware que convierte texto y varias órdenes de voz enviados a la salida de voz.
  • Variable: un marcador de posición temporal para algunos datos.

Apéndice B: Programación y conceptos de Python que todo desarrollador de complementos necesita saber

La siguiente lista resume los conceptos que todos los desarrolladores de complementos necesitarán conocer cuando escriban complementos.

  • API: un conjunto de documentación y muestras de código utilizado para permitir que un programa o hardware interactúe con otro software o hardware.
  • Clase base: una clase que proporciona métodos base, atributos y propiedades para que otros objetos hereden y amplíen. Sinónimo de superclase y clase padre.
  • Clase hija: una clase que deriva su poder de una o más clases básicas.
  • Clase: definición de objetos, incluyendo métodos, atributos y comportamientos esperados. Todas las clases y atributos de Python son públicos; pueden “llegar a ser privados” mediante el uso de convenciones de nomenclatura como prefijar un nombre de variable con subrayados (_).
  • Bloque de código: colección de código.
  • Compilación: traducción de un lenguaje de programación de alto nivel a un lenguaje de programación de bajo nivel apto para la ejecución en máquina.
  • Programación dirigida por eventos: un paradigma de programación basado en el seguimiento, la reacción y el manejo de eventos.
  • Excepción: una o más circunstancias en tiempo de ejecución que impiden el funcionamiento normal de un programa, como negarle el acceso a un recurso, problemas de uso del nombre en el código y otros casos.
  • GUI: Interfaz gráfica de usuario.
  • Manejador: una referencia opaca a un recurso tal como un archivo, socket TCP, ventana, etcétera.
  • Relación tiene vs. es: el primero se refiere a atributos de una sola clase, y el segundo a clases heredadas.
  • Sintaxis basada en la indentación: uso de indentaciones tales como tabulaciones para denotar bloques de código.
  • Herencia: habilidad para que una o más clases padres provean métodos y atributos básicos para que las clases hijas sobreescriban o amplíen según surja la necesidad.
  • Interpretar: ejecutar un programa escrito en un lenguaje de alto nivel sin compilarlo primero.
  • Objeto: instancia de ejecución de una o más clases.
  • Jerarquía de objetos: cómo se organizan los elementos de pantalla mediante la relación padre-hijo (contenedor – contenido).
  • Programación orientada a objetos: un paradigma de programación que define soluciones a problemas o representa cosas reales a través de clases y objetos.
  • Alcance: dónde las variables, funciones, clases y objetos se definen en código.

Apéndice C: Comparación de tipos de complementos

La siguiente tabla compara varios tipos de complementos y cuándo utilizarlos.

Tarea o característica Extensión global Módulo de aplicación Controlador
Puede usarse en todas partes No
Restricciones de nombrado No (limitado por las convenciones de nombrado de ficheros de Windows) Debe llamarse como el ejecutable No (limitado por las convenciones de nombrado de ficheros de Windows)
Recupera varios controles, incluyendo el control enfocado No
Las órdenes pueden utilizarse en cualquier lugar No Sólo los controladores de pantalla braille si se definió
Manejar eventos tales como cambios del foco No
Definir objetos personalizados para representar controles No
Definir acciones personalizadas al realizarse cuando el módulo se cargue y se descargue
Definir acciones personalizadas a realizarse cuando ocurran cambios de perfil y otros eventos
Puede modificar atributos de objeto en tiempo de ejecución No No
Modifica rutinas de salida de voz y otras y la experiencia de presentación (Por ejemplo speech.cancelSpeech, braille.handler.update, etc.) No
Incluir opciones personalizadas Sólo sintetizadores de voz
Puede parchear funciones de NVDA, classes y módulos a voluntad No se aconseja No
Sujeto a cambios de perfil de configuración No
Puede llamar a bibliotecas externas escritas en C y otros lenguajes y empaquetadas como DLLs

Apéndice D: notas y referencias para creadores de scripts de otros lectores de pantalla

Si escribes scripts para lectores de pantalla como JAWS para Windows o Window-Eyes, asegúrate de repasar esta sección ya que te presenta las tareas comunes que puedes realizar con NVDA y otras notas.

Tarea función /clase/módulo de NVDA o de Python Notas
Cancelar voz speech.cancelSpeech() Detiene la voz.
Verbalizar algo speech.speakMessage(mensaje) o como parte de ui.message(mensaje) la función ui.message también realiza la salida braille.
Braillificar algo braille.handler.message(mensaje) o ui.message(mensaje) Igual que arriba.
Mostrar una ventana HTML ui.browseableMessage(mensaje, título, isHTML = True) Imita el visor virtual excepto a la hora de mostrarse en pantalla.
Recuperar objeto con el foco algo = api.getFocusObject()
Recuperar ventana en primer plano primerplano = api.getForegroundObject()
Título de la ventana activa (si está presente) foreground.name
Averiguar qué objeto es el navegador de objetos obj = api.getNavigatorObject() Este podrá ser o no ser el control enfocado.
Recuperar el manejador de ventana para un objeto dado hwnd = obj.windowHandle Obtiene el objeto a través de las funciones api.get*Object().
Comprobar el nombre de la clase de ventana obj.windowClassName == algo
Asegurarse de que el objeto padre tiene el ID de control de ventana correcto if obj.parent.windowControlID == algo: instrucciones
El objeto padre no proporciona lo que yo quiero, pero el abuelo lo hace algo = obj.parent.parent.atributo
La etiqueta de un elemento de lista es el nombre de su primer objeto hijo. obj.name = obj.firstChild.name
Deseo que la etiqueta de control del objeto enfocado y la descripción del objeto anterior se anuncien cuando pulso NVDA+Tab En reportFocus(self): obj.name += ” ” + obj.previous.description
Anunciar si el estado cambia si y sólo si el siguiente objeto es la barra de herramientas que estoy buscando. In event_stateChange(self): toolbar = obj.next; if toolbar.role == controlTypes.ROLE_TOOLBAR and toolbar.attribute = loqueestoybuscando y condiciones adicionales …: instrucciones Para una mejor legibilidad, coloca cada declaración en líneas separadas con indentaciones correctas.
Anunciar el nombre de un objeto en pantalla (siempre que se pueda utilizar la navegación por objeto) obj = api.getForegroundObject().ruta…; ui.message(obj.name) Trata de colocar cada sentencia en su propia línea con las indentaciones correctas aplicadas. La ruta se refiere a obj.next/previous/parent/firstChild/lastChild/children[index]/getChild(index) y así sucesivamente.
Comprueba si el rol del objeto es el que deseas obj.role == controlTypes.ROLE_* ROLE_* puede ser cualquier rol que estés buscando.
Búsqueda de un texto específico en el nombre del objeto textobuscado in obj.name Esta es una tarea típica de los miembros de una cadena de texto.
¿Empieza la etiqueta del control con un texto específico? obj.name.startswith(textobuscado)
Longitud de un campo de texto con valor fácilmente recuperable len(obj.value) Esto funciona si se puede encontrar el valor del campo.
Es una casilla marcada controlTypes.STATE_CHECKED in obj.states obj.states es un conjunto. En primer lugar, verifica que el rol es de una casilla de verificación.
Cuántos elementos hay en una lista algunaLista.childCount Siempre que la lista proporcione una correcta implementación subyacente para obtener el recuento de elementos.
Dónde se encuentra el objeto en la pantalla obj.location Esto devuelve una tupla de cuatro elementos, es decir, coordenadas x e y de la esquina superior izquierda del objeto, así como longitud y anchura. Por ejemplo, en el objeto Shell (escritorio) con una resolución de pantalla de 1920 por 1080 píxeles, el valor de retorno será (0,0,1920,1080).
¿Es este un control MSAA? isinstance(obj, NVDAObjects.IAccessible.IAccessible) Una implementación típica es importar IAccessible desde NVDAObjects.IAccessible y hacer isinstance(obj, IAccessible).
Posición de un elemento de lista MSAA item.IAccessibleChildID Siempre y cuando esto se implemente correctamente. El valor predeterminado para los controles que no sean elementos de lista o elementos de vista de árbol es 0.
Necesito trabajar con métodos de un objeto IAccessible directamente obj.IAccessibleObject.method primero, descubre cómo usar el método MSAA dado para un control, y después recupera el propio objeto IAccessible y llama al método.
Dame el elemento UIA que proporciona un control UIA obj.UIAElement útil si quieres realizar operaciones de cliente UIA en este elemento.
ID de automatización para un elemento UIA obj.UIAElement.cachedAutomationID Primero, comprueba si el objeto es un control UIA.
Framework utilizado para generar este objeto UIA obj.UIAElement.cachedFrameworkID El framework GUI utilizado para programar este objeto. Los frameworks más comunes son Direct UI, Windows Presentation Foundation (WPF) con UIA habilitado, XAML (lenguaje extensible de programación de aplicaciones) y Microsoft Edge.
Quiero pedirle a UIA los valores de una propiedad específica obj._getUIACacheablePropertyValue(propertyID) asumiendo que el objeto es un control UIA, pásale el identificador de la propiedad que quieres conocer como argumento de esta función. Si la propiedad está soportada, se devolverá un valor válido. Si no, se lanzará un error COM.
Nombre ejecutable de cualquier objeto obj.appModule.appName appModule es el atributo de cualquier objeto que se pueda representar dentro de una aplicación como el control enfocado.
Enviar combinaciones de teclas gesture.send() Se debe llamar desde un script asociado a la combinación de teclas deseada.
Manejo de múltiples pulsaciones de teclas scriptHandler.getLastScriptRepeatCount() 0 significa que la orden se ha pulsado una vez.
Quiero asignar la fila Control+Alt+número a un script En initOverlayClass(self): for key in range(10): self.bindGesture(“control+alt+%s”%(key), “elscript”) Para Python 2, utiliza xrange en su lugar. Para facilidad de lectura, indenta cada sentencia en líneas separadas.
proporcionar mensajes de ayuda para entradas script_somescript.doc Efectivamente, la cadena de documentación del script se trata como su mensaje de ayuda para entradas.
Manejar los cambios de nombre event_nameChange(self, obj, nextHandler) El cuerpo debe consistir en lo que se debe hacer, terminando con una llamada a la función nextHandler ().
Anuncios de cambio de región viva event_liveRegionChange(self, obj, nextHandler) De forma predeterminada, el nuevo texto será hablado y/o braillificado.
Transformar instantáneamente una ventana en un diálogo En chooseNVDAObjectOverlayClasses(self, obj, clsList): si encuentras la ventana que quieres: clsList.insert(0, NVDAObjects.Behaviors.Dialog) Asegúrate de identificar que esta ventana es realmente un diálogo. Si se hace correctamente, los contenidos de este”diálogo” se anunciarán automáticamente.
Estoy trabajando con una ventana de terminal Hereda de NVDAObjects.behaviors.Terminal
Deseo añadir órdenes de navegación de tabla para un objeto que todavía no se muestra como tabla Hereda de NVDAObjects.behaviors.RowWithFakeNavigation Esta clase define el mensaje del modo de ayuda de entrada y una implementación básica para las órdenes de navegación de tabla (Control+Alt+flechas).
Necesito indicadores para proporcionar soporte mejorado para una aplicación Java NVDAObjects.JAB y módulo JABHandler Java Access Bridge (de 32 y 64 bits) debería instalarse.
Añadir soporte para una aplicación con funcionalidad similar a la de otra aplicación Importar contenidos del módulo de aplicación fuente a través de from nombremódulo import * Se conoce con el nombre de “Aliasing”.
Reproducir un tono tones.beep(hertz, duration) Duración en milésimas de segundo.
Reproducir un tono en el altavoz izquierdo tones.beep(hertz, duration, leftVolume=100, rightVolume=0)
Reproducir un fichero de sonido wav nvwave.playWaveFile(path) Por ejemplo, nvwave.playWaveFile(r”test.wav”)
Obtener información de texto para un objeto determinado obj.TextInfo Observa la “T” mayúscula.
Comprobar si el eco de teclado (caracteres tecleados) está activado config.conf[“keyboard”][“speakTypedCharacters”]
activar la verbalización de las teclas de órdenes sin abrir el cuadro de diálogo de configuración config.conf[“keyboard”][“speakCommandKeys”] = True El usuario debe activar esto a través del diálogo de opciones de teclado.
El Modo foco/modo formularios está activo obj.treeInterceptor.passThrough Si es true, el modo foco/modo formularios está activado mientras se utilizan los documentos del modo exploración.
Dispone de soporte para pantalla táctil touchHandler.handler is not None Si no es None, el soporte táctil está activo y disponible.
Obtener la versión de NVDA versionInfo.version
Quiero hacer algo cada vez que cambien los perfiles de configuración config.configProfileSwitch debes registrar una función que escuche esta acción, y hacer que haga algo cada vez que los perfiles cambien.
Hazme saber si esta es una versión de desarrollo debug Si esta variable es True, la versión actual es de desarrollo. En cualquier otro caso, es una liberación oficial.
Necesito ciertas características para que mi código funcione mejor hasattr(módulo, algo) esto te permite comprobar la existencia de una característica o atributo que puedas necesitar, de tal forma que puedas dar soporte a versiones antiguas y nuevas del código.
Versión de Windows sys.getwindowsversion Esto devuelve una tupla de cinco elementos: versión principal, versión menor, número de compilación, plataforma y versión del Service Pack.
¿Es Windows de 64 bits? os.environ(“PROCESSOR_ARCHITEW6432”) in [“AMD64”, “ARM64″] o también os.path.exists(r”C:\Program Files (X86)”) El método variable de entorno es más fiable. A partir de 2017.4, se debe comprobar tanto AMD64 como ARM64, especialmente cuando se admite Windows 10 en ARM.
Acceso al registro Módulo _winreg Cambiado a “winreg” en Python 3.
Abrir un sitio web con el navegador web predeterminado os.startfile(URL)
Descargar cabeceras para un archivo en la web resource = urllib.urlopen(URL)
Trabajar con datos JSON Módulo json
Reservar algo de memoria en algún lugar ctypes.windll.kernel32.VirtualAllocEx() La forma más rápida de hacerlo es la función winKernel.virtualAllocEx.
Enviar un mensaje a otro proceso ctypes.windll.user32.SendMessageW() El camino más corto es la función winUser.sendMessage().
Hora actual en segundos time.time() Devuelve segundos transcurridos desde el 1 de enero de 1970 a medianoche.
Crear un cuadro de mensaje gui.messageBox Una fina envoltura alrededor de la clase wx.MessageBox.
Crear un diálogo personalizado wx.Dialog
Ejecutar varias tareas en segundo plano a la vez threading.Thread En realidad, debido a problemas internos, Python ejecutará un hilo tras otro. Este enfoque es útil si deseas ejecutar una tarea en segundo plano mientras haces que NVDA siga respondiendo.
Ejecutar algo periódicamente wx.PyTimer o threading.Timer
Ocurrencia del recuento de texto en un documento collections.Counter Asegúrate de tener una lista de palabras de un archivo de texto antes de ejecutar una cuenta en él.
Crear una matriz dinámica Objeto list El objeto de lista de Python ([]) es una matriz dinámica.
Trabajar con matrices asociativas Objeto dict El objeto diccionario de Python ({}) es otro nombre para la matriz asociativa, a veces llamada mapa.
Abrir, analizar y guardar archivos de configuración módulo config o módulo configobj
Quiero que mi código se ejecute más rápido y sin errores ¡No lo hagas a menos que sea necesario! Citando a un conocido programador, “No optimices si no quieres tener dolores de cabeza”.
Quiero liberar la versión 1.0 de mi código con todo incluido ¡Nunca lo hagas a menos que sepas por qué, sepas qué estás haciendo o lo especifique un contrato que hayas firmado!
Me gustaría traer una función de otro lector de pantalla a NVDA Justifica por qué y planéalo adecuadamente
Quiero integrar funciones de mi complemento en el lector de pantalla NVDA Envía una solicitud de cambios y prepárate para responder a las preguntas de los revisores A veces, una o dos características de un complemento aterrizan en el lector de pantalla NVDA, pero después de pasar por un proceso de revisión en una solicitud de cambios. Para más información, mira las pautas de contribución de NV Access.