# 3. Γράφοντας νέες πρόσθετες λειτουργίες

Επέκταση του Accerciser με τις επιθυμητές σας λειτουργίες
Eitan Isaacson
eitan@ascender.com
Peter Parente
pparent@us.ibm.com
Aline Bessa
alibezz@gmail.com

Creative Commons Share Alike 3.0

Μάριος Ζηντίλης
m.zindilis@dmajor.org 2009
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2012

# Γράφοντας πρόσθετα για το Accerciser

Η επέκταση του Accerciser με νέα πρόσθετα έγινε ευκολότερη χάρη σε αυτόν τον οδηγό. Δεδομένου ότι παρέχει μια πολύ λεπτομερή εξήγηση σχετικά με το θέμα, η ενότητα αυτή αποτελείται από το πρωτότυπο περιεχόμενό του και έγιναν μόνο απλές εκδόσεις και ενημερώσεις.

Το Accerciser υποστηρίζει τρεις βασικούς τύπους πρόσθετων λειτουργιών:

Βασικά πρόσθετα - Αυτά τα πρόσθετα προέρχονται από την κλάση των βασικών πρόσθετων. Δεν παρέχουν μια ορατή διεπαφή, αλλά προσφέρουν επιπρόσθετη λειτουργικότητα στο Accerciser.

Πρόσθετα κονσόλας - Αυτά τα πρόσθετα εμφανίζουν την έξοδο της κονσόλας σε μια περιοχή κειμένου στην καρτέλα ενός πρόσθετου. Μην το μπερδεύετε με το πρόσθετο κονσόλας IPython.

Πρόσθετα προβολής - Είναι η πλειονότητα των προεπιλεγμένων προσθέτων του Accerciser. Προσφέρουν μια προσαρμοσμένη γραφική διεπαφή σε μια καρτέλα.

# Δημιουργία μιας βασικής πρόσθετης λειτουργίας

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

Αρχικά, οι εισαγωγικές γραμμές που θα χρησιμοποιήσουμε είναι:

from accerciser.plugin import Plugin import gtk import pyatspi

Στη συνέχεια θα παράξουμε μια νέα κλάση από την κλάση της βάσης, και θα ορίσουμε κάποια βασικά ορίσματα στην κλάση:

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

Τώρα θα διαγράψουμε την αρχική μέθοδο, στην οποία θα ορίσουμε το καθολικό κλειδί ενέργειας για την επιλογή του τελευταίου προσβάσιμου αντικειμένου. Θα εγγράψουμε ένα listener για το συμβάν "focus" και θα ορίσουμε τη μεταβλητή last_focused σε 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

Παρατηρείστε ότι η μεταβλητή global_hotkeys είναι μια σειρά από λίστες. Κάθε σειρά αντιστοιχεί σε μια καθολική ενέργεια συντόμευσης, αποτελούμενη από μια περιγραφή της ενέργειας, την επιθυμητή μέθοδο κλήσης, ένα σύμβολο για το πάτημα του πλήκτρου και τον τροποποιητή κλειδιού.

Στο γεγονός επανάκλησης "focus", αντιστοιχούμε τη μεταβλητή last_focused στο προσιτό αντικείμενο που δημιούργησε το γεγονός "focus".

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

Στην ενέργεια επανάκλησης της συντόμευσης, ενημερώνουμε τον κόμβο της εφαρμογής με το τελευταίο εστιασμένο προσιτό αντικείμενο, οπότε έχουμε:

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

# Δημιουργία πρόσθετης λειτουργίας κονσόλας

Θα δημιουργήσουμε ένα πρόσθετο κονσόλα που θα εμφανίζει τις αλλαγές εστίασης που δημιουργούνται από ένα προσιτό αντικείμενο με ρόλο "push button" - θυμηθείτε πως είναι εύκολο να ελέγξετε ποιος είναι ο ρόλος οποιοδήποτε αντικειμένου στο Accerciser. Για παράδειγμα, μπορείτε να το επιβεβαιώσετε στη δενδρική προβολή των εφαρμογών.

Οι απαιτούμενες εισαγωγικές γραμμές είναι:

from accerciser.plugin import ConsolePlugin import pyatspi

Μετά θα ορίσουμε μια κλάση, με το όνομα του πρόσθετου και μια περιγραφή:

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

Αντικαθιστούμε την αρχική μέθοδο προσθέτοντας έναν εγγεγραμμένο listener:

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

Στη μέθοδο επανάκλησης, εκτυπώνονται όλα τα γεγονότα πατήματος των πλήκτρων.

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

# Δημιουργία πρόσθετης λειτουργίας προβολής

Θα δημιουργήσουμε ένα πρόσθετο προβολής που επιτρέπει τη γρήγορη δοκιμή της ενέργειας "click" στα προσβάσιμα αρχεία που υποστηρίζουν την ενέργεια διεπαφής AT-SPI και έχουν μια ενέργεια με όνομα "click". Θα είναι ένα απλό κουμπί, που μόλις πατηθεί, θα κάνει την ενέργεια του "click" στο αντικείμενο.

Αρχικά, μερικές υποχρεωτικές εισαγωγικές γραμμές:

import gtk from accerciser.plugin import ViewportPlugin

Στη συνέχεια, μια κλάση ορισμού, με όνομα και περιγραφή:

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

Δημιουργήσαμε μια εύκολη μέθοδο που επιστρέφει μια λίστα των υποστηριζόμενων ενεργειών του επιλεγμένου προσβάσιμου αντικειμένου - αν δεν υποστηρίζει την ενέργεια διεπαφής επιστρέφει μια κενή λίστα:

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

Η κλάση των βασικών πρόσθετων έχει τη μέθοδο onAccChanged που καλείται κάθε φορά που αλλάζει το προσιτό αντικείμενο της επιθυμητής εφαρμογής. Θα το αντικαταστήσουμε ορίζοντας το κουμπί να είναι μόνο ενεργό όταν το τρέχον αντικείμενο έχει την ενέργεια "click":

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

Η μέθοδος επανάκλησης για το κουμπί "clicked" εκτελεί την ενέργεια "click" για το προσιτό αντικείμενο. Από τη στιγμή που η επανάκληση μπορεί να καλεστεί μόνο όταν το κουμπί είναι ενεργό, δεν χρειάζεται να ανησυχείτε αν το τρέχον προσιτό αντικείμενο ένα την ενέργεια "click" ;

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