Implementing accessibility

Accessibility for third-party applications

The ocempgui.access module provides a wrapper around the ATK accessibility library and several classes to ease the development of accessible applications. To serve different ability ranges, objects can be aware, the ATK developers use an C interface system, that has to be implemented for each toolkit. OcempGUI implements those interfaces using the AtkObject only and flags, that will enable or disable certain interfaces within that instance.

To use accessibility features in your code, you have to import the module using:

import
        ocempgui.access
If you plan to integrate ATK support for third-parts accessibility solutions in your code, you should import the papi module in your code so you can use the ATK wrapper system.
import ocempgui.access.papi

Making python objects accessible

To make python objects accessible and usable by accessibility-aware applications and hardware they should implement IAccessible interface class. It provides a single method interface, get_accessible(), which has to return an AtkObject object for the specific python instances.

class A11yObject (IAccessible):
    def __init__ (self):
        IAccessible.__init__ (self)
        ...
    def get_accessible (self):
        obj = AtkObject (...)
        ...
        return obj
        

Dependant on the capabilities of the python object and the information it provides, it has to set up several attributes and/or implement various interfaces of the AtkObject, which will be returned.

TODO: provide more details

You can find the following example as a python script under examples/a11y_test.py.

# papi test example.
import ocempgui.access.papi as papi
import atexit

# Main object - somewhat similar to the GailTopLevel object.
application = papi.AtkObject ()
application.name = "Application object"
application.description = "Application description"
application.role = papi.ATK_ROLE_APPLICATION
application.parent = None

def get_application ():
    global application
    return application

# Register the interfaces and initialize the atk-bridge.
papi.set_atk_root (get_application)
atexit.register (papi.shutdown)
papi.init ()

class SimpleA11y (papi.AtkObject):
    def __init__ (self):
        ifaces = papi.ATK_IFACE_COMPONENT | papi.ATK_IFACE_ACTION
        papi.AtkObject.__init__ (self, ifaces)

        # Implement some interfaces of ATK_IFACE_ACTION and
        # ATK_IFACE_COMPONENT.
        self.action_get_n_actions = self.__get_n_actions
        self.action_get_description = self.__get_description
        self.action_get_name = self.__get_name
        self.component_get_extents = self.__get_pos

    def __get_pos (self, coords):
        return 10, 10, 99, 99
    
    def __get_n_actions (self):
        return 1

    def __get_description (self, i):
        return "Example action."

    def __get_name (self, i):
        return "Example action name"
    
# Window dummy as child of the toplevel application object.
window = SimpleA11y ()

# Retrieve the state set, so we can set it active.
set = window.ref_state_set ()
set.add_state (papi.ATK_STATE_ACTIVE)

# Set some necessary information for accessibility applications.
window.role  = papi.ATK_ROLE_WINDOW
window.name = "Window A11y Object"
window.description = "Window Description"

# Link it with the application object
window.parent = application

# Signal testing - window:create will cause accessibility applications
# to note, that a new window was created for the application.
window.emit ("window:create")

print "Keeping myself alive. Press CTRL-C to exit the application."
while True:
    # Iterate the main processing loop of the ATK wrapper internals,
    # so that external applications can interact with the objects.
    papi.iterate ()

Example 1. ocempgui.access.papi test example


Keyboard navigation - IIndexable

Unhide the screen - the Magnifier

The Magnifier class of the ocempgui.access module is a screen magnification tool for pygame screens. It allows users to zoom portions of the current pygame screen, which are determined by the mouse cursor position. It allows different magnification factors and a variable sizing of the area to zoom.

The Magnifier can be integrated easily into any pygame mainloop and adjusted with minimal effort. To create a new instance of it, you simply can invoke its constructor with no arguments.

magnifier = Magnifier ()
        
Alternatively you can also pass the initial area size to magnify and the zoom factor.
# Use a magnification area of 100, 100 and a factor of 3.
magnifier = Magnifier (100, 100, 3)
        

The zoom factor can be adjusted using the factor attribute and set_factor() method.

magnifier.factor = 5.2
magnifier.set_factor (0.5)
        

Note

Values smaller than 1 will zoom out the affected area.

The size of the area around the mouse cursor, which should be magnified, can be adjusted using the size attribute and set_size() method.

magnifier.size = 50, 50
magnifier.set_size (40, 70)
        
The resulting magnification area will be the size multiplicated with the set factor and be centered at the current mouse position.

Integrating the Magnifier in a pygame application is done by just adding one or two lines of code. The most important line is to notify it about the available pygame events.

while True:
    events = pygame.event.get ()
    magnifier.notify (*events)
    ...
        
This will enable it to react and refresh the magnified area and its position correctly upon the occurance of pygame.MOUSEMOTION events. Any other event will cause it to update its area only.

Note

The update is done only once per notify() invocation. If multiple pygame.MOUSEMOTION events are in the passed list, only the last on will be used for repositioning.

If the pygame display is manipulated directly and thus needs to contain its original surface information (without the magnified area), the restore() method should be invoked before the manipulation occurs.

while True:
    events = pygame.event.get ()

    magnifier.restore ()

    # Display manipulation
    ....
    
    magnifier.notify (*events)
    ...
        
This ensures that the original display contents are restored (the Magnifier will be suspended) before any manipulation takes place. Afterwards the Magnifier will be enabled again by passing the current events to it.

The Magnifier allows you to setup your own zoom function for best results when zooming parts of your application screen. The zoom_func attribute and set_zoom_func() method allow you to provide an own zoom function, which has to return the zoomed surface. It receives additional arguments, which are explained in detail in the inline documentation of the Magnifier class.

Implementing the Magnifier's default zoom function could be achieved using the following code.

def own_zoom_func (screen, mousepos, resultsize, size, factor):
    offset = mousepos[0] - size[0] / 2, mousepos[1] - size[1] / 2
    # Create zoomable surface.
    surface = pygame.Surface ((size[0], size[1]))
    surface.blit (screen, (0, 0), (offset[0], offset[1], size[0], size[1]))
    # Zoom and blit.
    return pygame.transform.scale (surface, (resultsize[0], resultsize[1]))

# Assign the new zoom function.
magnifier.zoom_func = own_zoom_func