# 3. Skriva nya instick

Utöka Accerciser med dina önskade funktioner
Eitan Isaacson
eitan@ascender.com
Peter Parente
pparent@us.ibm.com
Aline Bessa
alibezz@gmail.com

Creative Commons DelaLika 3.0

Daniel Nylander
po@danielnylander.se 2007
Anders Jonsson
anders.jonsson@norsjovallen.se 2017
Sebastian Rasmussen
sebras@gmail.com 2017

# Skriva instick för Accerciser

Att utöka Accerciser med nya instick blev mycket lättare sedan denna guide skrevs. Eftersom den tillhandahåller en väldigt detaljerad förklaring av ämnet så består detta avsnitt praktiskt taget av dess ursprungliga innehåll - endast enkla redigeringar och uppdateringar har gjorts.

Accerciser har stöd för tre grundläggande typer av instick:

Basinstick - Dessa instick härleds från basklassen Plugin. De tillhandahåller inte ett synligt gränssnitt, men kan tillhandahålla ytterligare funktionalitet för Accerciser.

Konsolinstick - Dessa instick tillhandahåller enkla konsolutdata till ett textområde i en flik för instick. Ej att förväxla med det paketerade insticket IPython-konsol.

Visningsområdesinstick - Majoriteten av Accercisers standardinstick. De tillhandahåller ett anpassat grafiskt gränssnitt i en flik.

# Skapa ett basinstick

Vi kommer att skapa en förenklad version av insticket Snabbväljare. Detta instick kommer att välja den senast fokuserade åtkomliga komponenten när du trycker på ctrl alt e.

Först och främst är de importrader vi kommer att använda:

from accerciser.plugin import Plugin import gtk import pyatspi

Härnäst kommer vi härleda en ny klass från basklassen Plugin, och tilldela några obligatoriska klassattribut:

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

Vi kommer nu att åsidosätta init-metoden, i vilken vi kommer att sätta en global tangentåtgärd för att välja det senaste fokuserade, åtkomliga objektet, registrera en händelselyssnare för ”fokus”-händelser och sätta instansvariabeln last_focused till 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

Notera att instansvariabeln global_hotkeys är en lista av tupler. Varje tupel är en global snabbknappsåtgärd, bestående av en åtgärdsbeskrivning, en önskad metod att anropa, en tangentsymbol för ett tangentnedslag samt en mask för tangentmodifierare.

I återanropet för ”fokus”-händelser, tilldelar vi instansvariabeln last_focused det åtkomliga objekt som just skickade ut ”fokus”-händelsen.

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

I återanropet för snabbtangentsåtgärden uppdaterar vi den programomfattande noden med det senast fokuserade åtkomliga objektet om vi har sparat det:

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

# Skapa en konsolinstick

Vi kommer att skapa ett konsolinstick för att visa fokusändringar som skickas ut av ett åtkomligt objekt med en ”tryckknapps”-roll - kom ihåg att det är enkelt att kontrollera vilken roll ett objekt har med Accerciser; du kan till exempel verifiera det i programträdvyn.

Import-rader som krävs:

from accerciser.plugin import ConsolePlugin import pyatspi

Sedan lägger vi till en klassdefinition med ett insticksnamn och beskrivning:

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

Vi åsidosätter init-metoden som lägger till en registerlyssnare:

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

I återanropsmetoden skrivs alla tryckknappshändelser ut.

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

# Skapa ett Visningsområdes-instick

Vi kommer att skapa ett visningsområdesinstick som tillåter snabbtestning av ”klick”-åtgärden för åtkomliga objekt som har stöd för AT-SPI-åtgärdsgränssnittet och har en åtgärd som heter ”click”. Det kommer att vara en enkel knapp som, när den klickas på, utför ”klick”-åtgärden i det åtkomliga objektet.

Först några nödvändiga import-rader:

import gtk from accerciser.plugin import ViewportPlugin

Sedan en klassdefinition med ett namn och beskrivning:

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

Vi åsidosätter init-metoden med lite användargränssnittsbyggande och ansluter ett återanrop till en signal för knappen. Vi använder justeringsbehållaren för att låta knappen centreras i insticksfliken och inte monstruöst ta upp hela insticksutrymmet. Notera att instansvariabeln plugin_area innehåller en gtk.Frame som kan fyllas med alla instickets komponenter.

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

Vi skapade också en bekvämlighetsmetod som returnerar en lista över åtgärder som stöds för det aktuellt markerade åtkomliga objektet - om det inte har stöd för Action-gränssnittet returnerar det en tom lista:

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

Basklassen för instick har ett metodanrop onAccChanged som anropas varje gång målprogrammets markerade åtkomliga objekt ändras. Vi kommer att åsidosätta den och sätta knappen så att den endast är känslig när det aktuella åtkomliga objektet har en ”klick”-åtgärd:

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

Återanropsmetoden för knapp-”tryck” utför ”klick”-åtgärden på det åtkomliga objektet. Då detta återanrop endast kan anropas när knappen är känslig behöver vi inte oroa oss för att kontrollera om det aktuella åtkomliga objektet har ”klick”-åtgärden.

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