# 3. Escrevendo novos plug-ins

Estendendo Accerciser com suas funcionalidades desejadas
Eitan Isaacson
eitan@ascender.com
Peter Parente
pparent@us.ibm.com
Aline Bessa
alibezz@gmail.com

Atribuição Compartilhada Igual 3.0 - Creative Commons

Enrico Nicoletto
liverig@gmail.com 2008.
Fabrício Godoy
skarllot@gmail.com 2008.
Leonardo Ferreira Fontenelle
leonardof@gnome.org 2008.
Rafael Fontenelle
rafaelff@gnome.org 2025.

# Escrevendo plug-ins para o Accerciser

Estender o Accerciser com novos plug-ins ficou muito mais simples desde que este tutorial foi escrito. Dado que ele fornece uma explicação muito detalhada sobre o tópico, esta seção consiste basicamente em seu conteúdo original - apenas edições e atualizações simples foram feitas.

Accerciser oferece suporte a três tipos básicos de plug-ins:

Plug-ins base - Esses plug-ins são derivados da classe base Plugin. Eles não fornecem uma interface visível, mas podem fornecer funcionalidade adicional ao Accerciser.

Plug-ins de console - Esses plug-ins fornecem saída de console simples em uma área de texto em uma aba de plug-in. Não deve ser confundido com o plug-in Console IPython empacotado.

Plug-ins de viewport - A maioria dos plug-ins padrão do Accerciser. Eles fornecem uma interface gráfica personalizada em uma aba.

# Criando um plug-in base

Criaremos uma versão simplificada do plug-in Seleção rápida. Este plug-in selecionará o último foco acessível ao pressionar ctrl alt e.

Primeiramente, as linhas de importação que usaremos são:

from accerciser.plugin import Plugin import gtk import pyatspi

Em seguida, derivaremos uma nova classe da classe base Plugin e atribuiremos alguns atributos de classe obrigatórios:

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

Agora, substituiremos o método init, no qual definiremos uma ação de tecla global para selecionar o último item acessível em foco, registraremos um ouvinte de evento para o evento "focus" e definiremos a variável de instância last_focused como 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

Observe que a variável de instância global_hotkeys é uma lista de tuplas. Cada tupla é uma ação de tecla de atalho global, composta por uma descrição de ação, um método desejado para chamar, um símbolo de tecla de pressionamento de tecla e uma máscara de modificador de tecla.

No retorno de chamada do evento "focus", atribuímos à variável de instância last_focused o item acessível que acabou de emitir o evento "focus".

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

No retorno de chamada da ação de tecla de atalho, atualizamos todo o nó do aplicativo com o último item acessível em foco, se o tivermos registrado:

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

# Criando um plug-in de console

Vamos criar um plug-in de console para exibir as alterações de foco emitidas por um item acessível com uma função de "botão de pressionamento" - lembre-se de que é fácil verificar qual é a função de qualquer item com o Accerciser; você pode verificar isso na Visão em Árvore de Aplicativos, por exemplo.

As linhas de importação necessárias são:

from accerciser.plugin import ConsolePlugin import pyatspi

Em seguida, adicionamos uma definição de classe, com um nome de plug-in e uma descrição:

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

Substituímos o método init adicionando um ouvinte de registro:

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

No método de retorno de chamada, todos os eventos de botão de pressionamento são impressos.

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

# Criando um plug-in de viewport

Vamos criar um plug-in de viewport que permite testes rápidos da ação "click" em itens acessíveis que suportam a interface Action do AT-SPI e têm uma ação chamada "clique". Será um botão simples que, uma vez clicado, faz a ação "click" no acessível.

Primeiramente, algumas linhas de importação obrigatórias:

import gtk from accerciser.plugin import ViewportPlugin

A seguir, uma definição de classe, com um nome e uma descrição:

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

Substituímos o método init com alguma construção de UI e conectamos um retorno de chamada a um sinal para o botão. Definimos o alinhamento para permitir que o botão seja centralizado na aba do plug-in e não ocupe monstruosamente todo o espaço do plug-in. Observe que a variável de instância plugin_area contém um gtk.Frame que pode ser preenchido com todos os widgets do plug-in.

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

Também criamos um método de conveniência que retorna uma lista de ações suportadas pelo item acessível selecionado no momento. Se ele não suportar a interface Action, ele retornará uma lista vazia:

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

A classe base do plug-in tem uma chamada de método onAccChanged que é chamada toda vez que o item acessível selecionado do aplicativo alvo muda. Nós a substituiremos definindo o botão para ser sensível somente quando o item acessível atual tiver a ação "click":

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

O método de retorno de chamada para o botão "clicked" executa a ação "click" no item acessível. Como esse retorno de chamada só pode ser chamado quando o botão é sensível, não precisamos nos preocupar em verificar se o acessível atual tem a ação "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'))