# 3. Neue Plugins schreiben

Accerciser
um gewünschte Funktionalitäten erweitern
Eitan Isaacson
eitan@ascender.com
Peter Parente
pparent@us.ibm.com
Aline Bessa
alibezz@gmail.com

Creative Commons Share Alike 3.0

Mario Blättermann
mario.blaettermann@gmail.com 2009, 2011, 2016
Max Orxy
maxorxy@googlemail.com 2012, 2013
Christian Kirbach
christian.kirbach@gmail.com 2012, 2013, 2016

# Plugins für Accerciser schreiben

Das Erweitern von Accerciser mit neuen Plugins wurde durch dieses Tutorial deutlich einfacher. In diesem Tutorial finden Sie eine sehr detaillierte Beschreibung des Themas. Der Abschnitt basiert im Wesentlichen auf dem ursprünglichen Inhalt - es gab nur einige simple Veränderungen und Aktualisierungen.

Accerciser unterstützt drei grundlegende Plugin-Typen:

Basis-Plugins - Diese Plugins stammen von der Basis-Plugin-Klasse. Sie stellen keine sichtbare Oberfläche zur Verfügung, aber können Accerciser zusätzliche Funktionalität bieten.

Konsolen-Plugins - Diese Plugins stellen eine einfache Konsolenausgabe in ein Textfeld in einem Plugin-Reiter zur Verfügung. Verwechseln Sie es nicht mit dem Paket IPython Konsolen-Plugin.

Ansichtsplugins - Das ist der Mehrheit der Standardplugins von Accerciser. Sie stellen eine spezifische grafische Oberfläche in einem Reiter zur Verfügung.

# Erstellen eines Basis-Plugins

We will create a simplified version of the Quick Select Plugin. This plugin will select the last focused accessible when pressing ctrl alt e.

Zunächst verwenden wir folgende Import-Zeilen:

from accerciser.plugin import Plugin import gtk import pyatspi

Anschließend leiten wir eine neue Klasse aus der Basis-Plugin-Klasse ab und ordnen einige obligatorische Klassenattribute zu:

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

Wir überschreiben nun die Anfangsmethode, und setzen ein globales Tastenkürzel, um das zuletzt angewählte barrierefreie Objekt auszuwählen, wir setzen einen Event-Listener für das »focus«-Ereignis und setzen die Instanzvariable last_focused auf 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

Hierbei werden Sie feststellen, dass die Instanzvariable global_hotkeys eine Liste von Tupeln ist. Jedes der Tupel ist ein Tastenkürzel, was aus einer Beschreibung der Aktion, der gewünschten Methode, die aufgerufen werden soll, einem Tastenkürzel, und einer Maske für die Änderung des Tastenkürzels besteht.

In der Callback-Funktion des »focus«-Ereignisses setzen wir die Variable last_focused auf die barrierefreie Anwendung, welche gerade das »focus«-Ereignis ausgelöst hat.

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

In the hotkey action callback, we update the application wide node with the last focused accessible item, if we have recorded it:

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

# Erstellen eines Konsolen-Plugins

Wir erstellen nun ein Konsolen-Plugin, um die Veränderungen des Fokus anzuzeigen, welche durch ein barrierefreies Objekt durch den »push button« ausgelöst werden - vergessen Sie dabei nicht, dass es mithilfe von Accerciser einfach ist festzustellen, welche die Funktion eines Objekts ist; das können Sie z.B. auch in der Anwendungsbaumansicht überprüfen.

Folgende Import-Zeilen werden benötigt:

from accerciser.plugin import ConsolePlugin import pyatspi

Dann definieren wir eine Klasse, mit dem Namen des Plugins und einer Beschreibung:

class PushButtonFocus(ConsolePlugin): plugin_name = 'Push Button Focus' plugin_description = 'Print event when pushbutton get\'s focus.'

Die Init-Methode wird überschrieben durch Hinzufügen eines Register-Lauschers:

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

In der Callback-Methode werden alle Ereignisse für Knopfbetätigungen ausgegeben.

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

# Erstellen eines Ansicht-Plugins

We will create a viewport plugin that allows quick testing of the "click" action in accessible items that support the AT-SPI Action interface and have an action named "click". It will be a simple button that, once clicked, does the "click" action in the accessible.

Zunächst einige grundlegende Import-Zeilen:

import gtk from accerciser.plugin import ViewportPlugin

Danach folgt eine Klassendefinition mit Name und Beschreibung:

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 use the alignment container 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): alignment = gtk.Alignment(0.5,0.5,0,0) self.click_button = gtk.Button('Click me!') alignment.add(self.click_button) self.plugin_area.add(alignment)

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

self.show_all()

Es wurde auch eine Methode erstellt die eine Liste der unterstützten Aktionen des aktuell ausgewählten Accessible-Objekts zurück gibt. Wenn es nicht die Schnittstelle »Aktion« unterstützt, so wird eine leere Liste zurück gegeben:

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

Die Basis-Pluginklasse hat eine Methode namens onAccChanged, die jedes mal aufgerufen wird, wenn sich das gewählte Accessible der Zielanwendung ändert. Dies wird durch Setzen des Knopfes als »druckempfindlich«überschrieben, für den Fall, dass das aktuelle Accessible die Aktion »Klicken« besitzt:

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

Die Callback-Methode für »angeklickt« führt die Aktion »Mausklick« auf dem Accessible-Objekt aus. Weil dieses Callback nur aufgerufen werden kann wenn der Knopf sensitiv ist, muss nicht geprüft werden, ob das aktuelle Accessible über die Aktion »Klick« verfügt.

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