# 3. Escribir complementos nuevos

Ampliar Accerciser con nuevas funcionalidades
Eitan Isaacson
eitan@ascender.com
Peter Parente
pparent@us.ibm.com
Aline Bessa
alibezz@gmail.com

Creative Commons Compartir Igual 3.0

Daniel Mustieles
daniel.mustieles@gmail.com 2011 - 2020
Jorge González
jorgegonz@svn.gnome.org 2007-2011

# Escribir complementos para Accerciser

Extender Accerciser con complementos nuevos se convirtió en algo muy sencillo desde que se escribió este tutorial. Proporciona una explicación muy detallada sobre el tema; esta sección consta básicamente del contenido original (sólo se han hecho pequeñas ediciones y actualizaciones).

Accerciser soporta tres tipos de complementos básicos:

Complementos base: estos complementos se derivan de la clase base «Plugin». No proporcionan una interfaz visible, pero pueden proporcionar funcionalidad adicional a Accerciser.

Complementos de consola: estos complementos proporcionan una sencilla consola de entrada en una área de texto en la pestaña de un complemento. No se confunda con el complemento de la Consola IPython incluido.

Complementos visuales: la mayoría de los complementos predeterminados de Accerciser. Proporcionan una interfaz gráfica en una pestaña.

# Crear un complemento base

Se creará una versión simplificada del complemento de selección rápida. este complemento seleccionará el último accesible con el foco al pulsar Ctrl Alt e.

Lo primero, las líneas de importación que se usarán son:

from accerciser.plugin import Plugin import gtk import pyatspi

Lo siguiente será derivar una clase nueva de la clase base de complementos, y asignar algunos atributos obligatorios de clase:

class FocusSelect(Plugin): plugin_name = 'Focus Select' plugin_description = 'Allows selecting last focused accessible.'

Ahora se sobrescribirá el método «init», en el que se establecerá una acción de clave global para seleccionar el último elemento accesible con el foco, registrar un «listener» de eventos para el evento «focus», y establecer la variable de instancia last_focused a None.

def init(self): pyatspi.Registry.registerEventListener(self.accEventFocusChanged, 'focus') self.global_hotkeys = [('Inspect last focused accessible', self.inspectLastFocused, gtk.keysyms.e, gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK)] self.last_focused = None

Note que la variable de instancia global_hotkeys es una lista de tuplas. Cada tupla es una acción de tecla rápida global, compuesta por una descripción de la acción, un método al que llamar, un símbolo de tecla de pulsación y una máscara modificadora.

En el evento de retorno de llamada de «focus», se asigna la variable de instancia last_focused con el elemento accesible que acaba de emitir el evento «focus».

def accEventFocusChanged(self, event): if not self.isMyApp(event.source): self.last_focused = event.source

En el retorno de llamada de la acción de la tecla rápida se actualiza el nodo amplio de la aplicación con el último elemento que tuvo el foco, si se guardó:

def inspectLastFocused(self): if self.last_focused: self.node.update(self.last_focused)

# Crear un complemento de consola

Se creará un complemento de consola para mostrar los cambios de foco emitidos por un elemento accesible con un rol de «pulsar botón»; recuerde que es muy fácil comprobar el rol de cualquier elemento en Accerciser, puede comprobarlo en la vista en árbol de la aplicación, por ejemplo.

Las líneas de importaciones necesarias son:

from accerciser.plugin import ConsolePlugin import pyatspi

Se añade entonces una definición de clase, con un nombre para el complemento y una descripción:

class PushButtonFocus(ConsolePlugin): plugin_name = 'Push Button Focus' plugin_description = 'Imprimir evento cuando el pulsador obtiene el foco.'

Se sobrescribe el método «init» añadiendo un registro de «listener»:

def init(self): pyatspi.Registry.registerEventListener(self.accEventFocusChanged, 'focus')

En el método de retorno de llamada se imprimen todos los eventos de pulsaciones de botones.

def accEventFocusChanged(self, event): if event.source.getRole() == pyatspi.ROLE_PUSH_BUTTON: self.appendText(str(event)+'\n')

# Crear un complemento de punto de vista

Se creará un complemento de puerto de vista que permite una prueba rápida de la acción de pulsación sobre elementos accesibles que soportan la interfaz AT-SPI Action y tienen una acción llamada «click». Será un botón simple que, una vez pulsado, realiza la acción de pulsación sobre el accesible.

En primer lugar, algunas líneas de importación obligatorias:

import gtk from accerciser.plugin import ViewportPlugin

Lo siguiente es una definición de clase, con un nombre y una descripción:

class Clicker(ViewportPlugin): plugin_name = 'Clicker' plugin_description = 'Test the "click" action in relevant accessibles.'

We override the init method with some UI building, and connecting a callback to a signal for the button. We set the alignment to allow the button to be centered in the plugin tab, and not monstrously take up the entire plugin space. Notice that the plugin_area instance variable contains a gtk.Frame that could be populated with all the plugin's widgets.

def init(self): self.click_button = gtk.Button('Click me!') self.click_button.set_halign(gtk.Align.CENTER) self.click_button.set_valign(gtk.Align.CENTER) self.plugin_area.add(self.click_button)

self.click_button.connect('clicked', self.onClick)

self.show_all()

También se ha creado un método de conveniencia que devuelve una lista de las acciones soportadas por el elemento accesible actualmente seleccionado; si no soporta la acción de la interfaz, entonces devuelve una lista vacía:

def accSupportedActions(self): try: ai = self.node.acc.queryAction() except NotImplementedError: action_names = [] else: action_names = [ai.getName(i) for i in xrange(ai.nActions)] return action_names

Esta clase de complemento base tiene una llamada de método onAccChanged a la que se llama cada vez que el elemento accesible seleccionado de la aplicación objetivo cambia. Se sobrescribirá ajustando el botón para ser sensible sólo cuando el elemento accesible actual tiene la acción «click».

def onAccChanged(self, acc): has_click = 'click' in self.accSupportedActions() self.click_button.set_sensitive(has_click)

El método del retorno de llamada para el botón pulsado realiza la acción de pulsación en el elemento accesible. Ya que a este retorno de llamada sólo se le puede llamar cuando el botón es sensible, no se debe preocupar acerca de comprobar si el accesible actual tiene la acción «cick».

def onClick(self, button): ai = self.node.acc.queryAction() action_names = [ai.getName(i) for i in xrange(ai.nActions)] ai.doAction(action_names.index('click'))