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.'
    

Se sobrescribirá el método «init» con una construcción de IU y conectando el retorno de la llamada a una señal para el botón. Se usará el contenedor de alineamiento para permitir que el botón esté centrado en la pestaña del complemento, y que no ocupe monstruosamente todo el espacio disponible. Note que la variable de instancia plugin_area gontiene un gtk.Frame que se puede llenar con todos los widgets del complemento.

       def init(self):
         alignment = gtk.Alignment(0.5,0.5,0,0)
         self.click_button = gtk.Button('Púlseme')
         alignment.add(self.click_button)
         self.plugin_area.add(alignment)

         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'))