NAME

Win32::ActAcc - `Active Accessibility' for task automation, GUI testing


SYNOPSIS

Win32::ActAcc gives Perl scripts free run of the Active Accessibility client API; IAccessible; and ``WinEvents''.

Active Accessibility lets Perl scripts see what's on the screen, even when programs use ``custom controls'', lightweight (drawn) controls that are not technically windows, and the like: VB for example.

You'll want to additionally use Win32::GuiTest, and other Win32 modules, if you want your script to click, type, manipulate the clipboard, etc.

 use Win32::OLE;
 use Win32::ActAcc;
 Win32::OLE->Initialize();
 # Start navigating window tree at its root -- the Desktop.
 $accObj = Desktop();
 @childAccObjs = $accObj->AccessibleChildren();
 $name = $accObj->get_accName();
 $rolename = Win32::ActAcc::GetRoleText($accObj->get_accRole());


DESCRIPTION

What does it all mean?

Win32::ActAcc broadly parallels the Active Accessibility spec.

This pod doesn't duplicate the Active Accessibility spec. See SEE ALSO.

Note to folks already acquainted with Active Accessibility: If you've programmed with Active Accessibility in C, you know first-hand that Active Accessibility was designed with the convenience of the server programmer in mind, and little regard for the happiness of the client. Clients often need not one, but two handles to refer to an accessible GUI feature - an IAccessible* and a ``child ID''. Win32::ActAcc wraps that pair of handles in a single Perl object representing each accessible GUI feature: Win32::AO, for Accessible Object.

This manual makes the following notational innovations:

  1. We preserve the name Microsoft chose for the methods and functions that come more or less straight out of the Active Accessibility SDK.

  2. Active Accessibility has some minor imperfections. Of course, Win32::ActAcc also has imperfections. To aid the reader in distinguishing the two, we have taken the liberty of calling out some ``Active Accessibility weirdnesses'' as such.

Samples

aaDigger.pl shows how to traverse the tree of accessible objects.

aaEvents.pl shows you the WinEvents that reflect what you're doing with the GUI.

aaWhereAmI.pl shows how to link a pixel location with its accessible object.

eg/aaAIMEliza.pl, at the risk of getting ridiculous, shows how to make Chatbot::Eliza respond to your incoming AOL Instant Messages. AIM is an application whose GUI is not made of standard controls, so this is an example of something you could not do (without constantly doing a File-Save As) with tools based on the Win32 API, window-classes and window-messages.

See under Tools for more about aaDigger, aaEvents, and aaWhereAmI.

Active Accessibility client API

The client API exposes jumping-off points like Desktop and AccessibleObjectFromWindow, and ``helper functions'' like GetRoleText.

If this is your first reading, you may want to read about Desktop and AccessibleObjectFromWindow in this section, then skip to Win32::ActAcc::AO.

Desktop

Obtain an ``accessible object'' representing the desktop, so you can call the object's Active Accessibility methods:

 $accObj = Desktop();
 die unless 'Win32::ActAcc::AO' eq ref($accObj);

The Desktop is a natural starting-point for traversing the tree of Accessible Objects.

Once you've got an accessible object, see Win32::ActAcc::AO on how to use it.

If you do not have a clear picture in mind of the accessible-object ``tree'' of which Desktop is the root, go try out the aaDigger.pl tool.

AccessibleObjectFromWindow

If you have an HWND, you can convert it to an Accessible Object with AccessibleObjectFromWindow:

 $accObj = AccessibleObjectFromWindow($hwnd);
 die unless 'Win32::ActAcc::AO' eq ref($accObj);

AccessibleObjectFromWindow's optional second parameter defaults to OBJID_WINDOW. Win32::ActAcc defines all the OBJID constants for Perl. (They come from WinAble.h.) See OBJID constants.

AccessibleObjectFromPoint

AccessibleObjectFromPoint checks the screen at the specified point and returns an accessible object representing the interactive item at that location.

 my $accObj = AccessibleObjectFromPoint($x, $y);

Speaking of ($x, $y), how do you figure out where the mouse is? You can subscribe to the WinEvents stream and watch for mouse location-change events. See sample aaEvents.pl to see how this works.

Not all ``accessible'' objects are in the Desktop-rooted hierarchy. Therefore, AccessibleObjectFromPoint may be the only way to access some ``accessible'' objects.

click

 Win32::ActAcc::click($xpix, $ypix, \$eh);

click() ``clicks'' somewhere on the screen, but first, it activates the optional event monitor, so you can capture the consequences of the click. See activate and menuPick.

You should use Win32::GuiTest for any extensive GUI manipulation. Win32::ActAcc's ``click'' method is not as flexible.

GetRoleText

Returns localized name of a role-number.

 my $chRole = Win32::ActAcc::GetRoleText($accObj->get_accRole());

GetStateText

Returns localized name of a state-number.

 my $statebit = Win32::ActAcc::STATE_SYSTEM_FOCUSED();
 my $statename = Win32::ActAcc::GetStateText($statebit);

Active Accessibility weirdness note: States are combinations of state-bits such as STATE_SYSTEM_FOCUSED (see STATE constants). GetStateText returns the name of only one of the bits that are set in the argument. If you want a quick way to get the whole truth about all the bits that are set, call GetStateTextComposite instead.

GetStateTextComposite

Returns a localized string of state texts, representing all of the turned-on state bits in the argument.

 $stateDesc = Win32::ActAcc::GetStateTextComposite( $accObj->get_accState() );

StateConstantName

Returns the C constant name for a state-bit defined in OleAcc.h (see STATE constants).

ObjectIdConstantName

Returns the C constant name for an object ID defined in OleAcc.h.

nav

nav finds a child Accessible Object by following a path from a starting point. The path specifies the name and/or role of each object along the path.

You can use nav to find the Start button. Giving undef as the starting point makes nav begin with the Desktop.

 $btnStart = Win32::ActAcc::nav(Desktop(), [ "{window}", "{window}Start", "{push button}Start" ] );

nav is also useful finding a control on a dialog:

 $accObjOk = Win32::ActAcc::nav($accObjDlg, [ "OK" ]);

menuPick

menuPick traverses a menu (starting with a menu bar), making a list of choices. Each choice is a regexp that must match one menu item. Right before making the final choice, menuPick activates your event monitor, so you can catch the consequences of the menu choice.

 my $menubar = ...
 my $ehDlg = Win32::ActAcc::createEventMonitor(0);
 menuPick($menubar, +[ qr/Format/, qr/Font/ ], \$ehDlg);
 $ehDlg->waitForEvent(
   +{ 'event'=>Win32::ActAcc::EVENT_SYSTEM_DIALOGSTART() });

(Note: menuPick is still experimental. It works with Notepad.)

CHILDID_SELF and lots of other constants

Use Win32::ActAcc constants as though they were functions:

 die unless (0 == Win32::ActAcc::CHILDID_SELF());

Win32::ActAcc provides the following Active Accessibility constants in addition to CHILDID_SELF and CCHILDREN_FRAME:

EVENT constants

EVENT_SYSTEM_SOUND, EVENT_SYSTEM_ALERT, EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MENUSTART, EVENT_SYSTEM_MENUEND, EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPEND, EVENT_SYSTEM_CAPTURESTART, EVENT_SYSTEM_CAPTUREEND, EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, EVENT_SYSTEM_CONTEXTHELPSTART, EVENT_SYSTEM_CONTEXTHELPEND, EVENT_SYSTEM_DRAGDROPSTART, EVENT_SYSTEM_DRAGDROPEND, EVENT_SYSTEM_DIALOGSTART, EVENT_SYSTEM_DIALOGEND, EVENT_SYSTEM_SCROLLINGSTART, EVENT_SYSTEM_SCROLLINGEND, EVENT_SYSTEM_SWITCHSTART, EVENT_SYSTEM_SWITCHEND, EVENT_SYSTEM_MINIMIZESTART, EVENT_SYSTEM_MINIMIZEEND, EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, EVENT_OBJECT_REORDER, EVENT_OBJECT_FOCUS, EVENT_OBJECT_SELECTION, EVENT_OBJECT_SELECTIONADD, EVENT_OBJECT_SELECTIONREMOVE, EVENT_OBJECT_SELECTIONWITHIN, EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_DESCRIPTIONCHANGE, EVENT_OBJECT_VALUECHANGE, EVENT_OBJECT_PARENTCHANGE, EVENT_OBJECT_HELPCHANGE, EVENT_OBJECT_DEFACTIONCHANGE, EVENT_OBJECT_ACCELERATORCHANGE

OBJID constants

OBJID_WINDOW, OBJID_SYSMENU, OBJID_TITLEBAR, OBJID_MENU, OBJID_CLIENT, OBJID_VSCROLL, OBJID_HSCROLL, OBJID_SIZEGRIP, OBJID_CARET, OBJID_CURSOR, OBJID_ALERT, OBJID_SOUND

STATE constants

STATE_SYSTEM_NORMAL, STATE_SYSTEM_UNAVAILABLE, STATE_SYSTEM_SELECTED, STATE_SYSTEM_FOCUSED, STATE_SYSTEM_PRESSED, STATE_SYSTEM_CHECKED, STATE_SYSTEM_MIXED, STATE_SYSTEM_INDETERMINATE, STATE_SYSTEM_READONLY, STATE_SYSTEM_HOTTRACKED, STATE_SYSTEM_DEFAULT, STATE_SYSTEM_EXPANDED, STATE_SYSTEM_COLLAPSED, STATE_SYSTEM_BUSY, STATE_SYSTEM_FLOATING, STATE_SYSTEM_MARQUEED, STATE_SYSTEM_ANIMATED, STATE_SYSTEM_INVISIBLE, STATE_SYSTEM_OFFSCREEN, STATE_SYSTEM_SIZEABLE, STATE_SYSTEM_MOVEABLE, STATE_SYSTEM_SELFVOICING, STATE_SYSTEM_FOCUSABLE, STATE_SYSTEM_SELECTABLE, STATE_SYSTEM_LINKED, STATE_SYSTEM_TRAVERSED, STATE_SYSTEM_MULTISELECTABLE, STATE_SYSTEM_EXTSELECTABLE, STATE_SYSTEM_ALERT_LOW, STATE_SYSTEM_ALERT_MEDIUM, STATE_SYSTEM_ALERT_HIGH, STATE_SYSTEM_PROTECTED, STATE_SYSTEM_VALID

ROLE constants

ROLE_SYSTEM_TITLEBAR, ROLE_SYSTEM_MENUBAR, ROLE_SYSTEM_SCROLLBAR, ROLE_SYSTEM_GRIP, ROLE_SYSTEM_SOUND, ROLE_SYSTEM_CURSOR, ROLE_SYSTEM_CARET, ROLE_SYSTEM_ALERT, ROLE_SYSTEM_WINDOW, ROLE_SYSTEM_CLIENT, ROLE_SYSTEM_MENUPOPUP, ROLE_SYSTEM_MENUITEM, ROLE_SYSTEM_TOOLTIP, ROLE_SYSTEM_APPLICATION, ROLE_SYSTEM_DOCUMENT, ROLE_SYSTEM_PANE, ROLE_SYSTEM_CHART, ROLE_SYSTEM_DIALOG, ROLE_SYSTEM_BORDER, ROLE_SYSTEM_GROUPING, ROLE_SYSTEM_SEPARATOR, ROLE_SYSTEM_TOOLBAR, ROLE_SYSTEM_STATUSBAR, ROLE_SYSTEM_TABLE, ROLE_SYSTEM_COLUMNHEADER, ROLE_SYSTEM_ROWHEADER, ROLE_SYSTEM_COLUMN, ROLE_SYSTEM_ROW, ROLE_SYSTEM_CELL, ROLE_SYSTEM_LINK, ROLE_SYSTEM_HELPBALLOON, ROLE_SYSTEM_CHARACTER, ROLE_SYSTEM_LIST, ROLE_SYSTEM_LISTITEM, ROLE_SYSTEM_OUTLINE, ROLE_SYSTEM_OUTLINEITEM, ROLE_SYSTEM_PAGETAB, ROLE_SYSTEM_PROPERTYPAGE, ROLE_SYSTEM_INDICATOR, ROLE_SYSTEM_GRAPHIC, ROLE_SYSTEM_STATICTEXT, ROLE_SYSTEM_TEXT, ROLE_SYSTEM_PUSHBUTTON, ROLE_SYSTEM_CHECKBUTTON, ROLE_SYSTEM_RADIOBUTTON, ROLE_SYSTEM_COMBOBOX, ROLE_SYSTEM_DROPLIST, ROLE_SYSTEM_PROGRESSBAR, ROLE_SYSTEM_DIAL, ROLE_SYSTEM_HOTKEYFIELD, ROLE_SYSTEM_SLIDER, ROLE_SYSTEM_SPINBUTTON, ROLE_SYSTEM_DIAGRAM, ROLE_SYSTEM_ANIMATION, ROLE_SYSTEM_EQUATION, ROLE_SYSTEM_BUTTONDROPDOWN, ROLE_SYSTEM_BUTTONMENU, ROLE_SYSTEM_BUTTONDROPDOWNGRID, ROLE_SYSTEM_WHITESPACE, ROLE_SYSTEM_PAGETABLIST, ROLE_SYSTEM_CLOCK

SELFLAG constants

SELFLAG_NONE, SELFLAG_TAKEFOCUS, SELFLAG_TAKESELECTION, SELFLAG_EXTENDSELECTION, SELFLAG_ADDSELECTION, SELFLAG_REMOVESELECTION, SELFLAG_VALID

NAVDIR constants

NAVDIR_MIN, NAVDIR_UP, NAVDIR_DOWN, NAVDIR_LEFT, NAVDIR_RIGHT, NAVDIR_NEXT, NAVDIR_PREVIOUS, NAVDIR_FIRSTCHILD, NAVDIR_LASTCHILD, NAVDIR_MAX

Win32::ActAcc::AO

IAccessible methods are in the Win32::ActAcc::AO package, so you can use them the object-oriented way.

Comparing Accessible Objects

AO's that map to HWNDs can be compared by getting their HWNDs and comparing those. Since AO's without HWNDs cannot be compared, you will want to avoid planning algorithms that depend on comparing accessible objects.

 $h1 = $ao1->WindowFromAccessibleObject();
 $h2 = $ao2->WindowFromAccessibleObject();
 if ($h1 == $h2) { ... }

You generally can't compare two AO objects directly because of the following weirdness.

Active Accessibility weirdness note: The default Active Accessibility server helper built into Windows to represent standard controls returns a new object in response to any query. If an Active Accessibility client requests the same accessible GUI feature several times, it gets several different IAccessible* pointers back.

Win32::ActAcc always uses the same Perl object for any given IAccessible-and-childID pair, so if you have a stable server (which you probably don't), you can take advantage in Perl.

describe

Produces human-readible (appropriate for debugging) description of an AO. Here's an example, with the fields labeled.

 window:emacs: ActAcc.pod {sizeable+moveable+focusable,(4,44,1009,663),id=0,000402e2}
 ^      ^--title/text      ^-- 'state' bits            ^               ^--ID                   
 |                                                     |                    ^-- HWND
 +-role                                                +-(left,top,width,height)

describe() isn't supposed to die. If something goes wrong, it returns an incomplete or empty string.

 print $accObj->describe();

If your script displays the results of describe() to its user, you might also want to print out describe_meta() at least once. It names the fields.

 print Win32::ActAcc::AO::describe_meta();

WindowFromAccessibleObject

Reverses AccessibleObjectFromWindow:

 $hwnd = $accObj->WindowFromAccessibleObject();

If no HWND corresponds to the object, WindowFromAccessibleObject dies, so you might want to run it inside an eval().

get_accName

Returns the 'name' property of the accessible object. For editable text and combo box objects, it appears this is the label Windows supposes the object has: it is usually identical to the text of the immediately-preceding text object. For windows, this is the title. For client areas, this is the same as the title of the enclosing window.

 $name = $accObj->get_accName();

Returns undef if the object doesn't have this property.

get_accRole

 $role = $accObj->get_accRole();

Returns a number, probably one of the Active Accessibility ROLE_ constants (see ROLE Constants). You can convert the number to a string with Win32::ActAcc::GetRoleText. Returns undef if the object doesn't have this property.

AccessibleChildren

 @ch = $accObj->AccessibleChildren();

Returns a list of the accessible objects that are children of $accObj. By default it omits the invisible children: the no-argument form of AccessibleChildren is short for

 @ch = $accObj->AccessibleChildren(Win32::ActAcc::STATE_SYSTEM_INVISIBLE(), 0);

The first parameter is a bit mask with 1's for the bits that matter as criteria, and the second parameter is the bit values to find in each of the '1' positions in the mask.

To find only the invisible children, you can use:

 @ch = $accObj->AccessibleChildren(
    Win32::ActAcc::STATE_SYSTEM_INVISIBLE(), 
        Win32::ActAcc::STATE_SYSTEM_INVISIBLE());

which means that the INVISIBLE bit should be included in the comparison, and it must be 1. See STATE constants.

Active Accessibility weirdness note: You will probably want to use AccessibleChildren() instead of get_accChildCount() and get_accChild(). AccessibleChildren probably calls those and then improves the results. But, AccessibleChildren frequently returns fewer children than get_accChildCount says it should.

Active Accessibility weirdness note: Some objects report 1 child with AccessibleChildren, yet accNavigate reveals more children. You can work around this problem by calling NavigableChildren instead. Note that NavigableChildren may have its own drawbacks.

In the Active Accessibility SDK, AccessibleChildren() is part of the API, not part of IAccessible.

NavigableChildren

Similar to AccessibleChildren, but uses accNavigate instead. Rule of thumb: Use AccessibleChildren unless it obviously is missing the children; in that case try NavigableChildren.

 my @ch = $menu->NavigableChildren();

get_accParent

 $p = $accObj->get_accParent();

Returns the parent object. Returns undef if the object has no parent.

get_accState

 $state = $accObj->get_accState();

Returns a number composed of bits defined by the Active Accessibility STATE_ constants (STATE_SYSTEM_NORMAL, etc.). See GetStateText and <``GetStateTextComposite''>.

Returns undef if the object doesn't have this property.

get_accValue

Returns the 'value' of the accessible object: the stuff in an editable text control, the outline-level of an outline item, etc.

 $value = $accObj->get_accValue();

Returns undef if the object doesn't have this property.

accLocation

 my ($left, $top, $width, $height) = $accObj->accLocation();

Returns the accessible object's location on the screen, in pixels. (0,0) is at the top left. Dies if the object doesn't have this property.

accNavigate

 my $smch = $accObj->accNavigate(Win32::ActAcc::NAVDIR_FIRSTCHILD());
 while (defined($smch))
 {
        my $n = $smch->get_accName();
        print STDERR "$n\n";
        $smch = $smch->accNavigate(Win32::ActAcc::NAVDIR_NEXT());
 }

Returns an Accessible Object representing one of the base object's relations. Win32::ActAcc defines the family of NAVDIR constants from OleAcc.h. See NAVDIR constants.

accNavigate does not move focus, nor perform any other action on behalf of the user.

get_accDescription

 $desc = $accObj->get_accDescription();

Returns undef if the object doesn't have this property. If you're trying to debug your script, describe is probably more appropriate, since it appears most accessible objects don't define their description.

get_accHelp

 $help = $accObj->get_accHelp();

Returns undef if the object doesn't have this property.

get_accDefaultAction

 $da = $accObj->get_accDefaultAction();

Returns undef if the object doesn't have this property.

get_accKeyboardShortcut

 $ks = $accObj->get_accKeyboardShortcut();

Returns undef if the object doesn't have this property.

get_accChildCount

 $nch = $accObj->get_accChildCount();

See AccessibleChildren.

get_accChild

 $ch = $accObj->get_accChild(3);

See AccessibleChildren.

get_accFocus

 $f = $accObj->get_accFocus();

accDoDefaultAction

 $accObj->accDoDefaultAction();

Active Accessibility weirdness note: Sometimes doesn't do anything.

get_itemID

 $plusOrDot = (Win32::ActAcc::CHILDID_SELF() == $ch[$i]->get_itemID()) ? '+' : '.';

get_itemID() returns the item-ID that is part of the identity of the accessible object.

accSelect

 $accObj->accSelect(Win32::ActAcc::SELFLAG_TAKEFOCUS());

See SELFLAG constants.

click

 $accObj->click(\$eh);

click() ``clicks'' the center of the accessible object, but first, it activates the optional event monitor, so you can capture the consequences of the click. See activate and menuPick.

findDescendant

Applies a code-ref or regexp to each child, grand-child, etc. In scalar context, returns the first Accessible Object for which the code-ref returns a true value, or for which the regexp indicates a match. In array context, returns a list of all matching Accessible Objects.

 $btnClose = $wNotepadApp->findDescendant( 
        sub{    
                my $n = $_->get_accName(); 
                (defined($n) && $n eq "Close") && 
                        ($_->get_accRole() == Win32::ActAcc::ROLE_SYSTEM_PUSHBUTTON()) 
        });

Release

 $accObj->Release();

Accessible objects are COM objects, so each one must be Released when you're done with it. Perl's garbage collector and Win32::ActAcc::AO conspire to automatically Release the accessible objects, so you should not need to call Release in your scripts.

WinEvents

WinEvents allow a script to keep apprised of windows appearing, disappearing, moving around, and so forth; and thereby to react to the consequences of an action.

For example, the script can press Start and then, by watching the event stream, latch onto the menu that comes up.

To watch the event stream, call createEventMonitor() and then use the EventMonitor's waitForEvent() or getEvent() method. Refer to the aaEvents sample.

See also Event Details.

createEventMonitor

 my $ehDlg = createEventMonitor(1);

createEventMonitor creates a Win32::ActAcc::EventMonitor object, which the script can poll for WinEvents using waitForEvent() or getEvent().

The ``1'' means the EventMonitor is immediately activated. Otherwise the EventMonitor is latent until activated, which typically happens in one of two ways:

EventMonitor

Here are the methods on the EventMonitor object you get from createEventMonitor.

waitForEvent

Sometimes, you want to see whether something happens. Other times, you know what will happen, but you want to find out which Accessible Object it happens to. waitForEvent() meets both needs.

Here's a sample of how to wait (for up to 30 seconds) for a Notepad window to appear.

 $aoNotepad = $eh->waitForEvent(
  +{ 'event'=>Win32::ActAcc::EVENT_OBJECT_SHOW(),
     'name'=>qr/Notepad/,
     'role'=>Win32::ActAcc::ROLE_SYSTEM_WINDOW() }, 30);

waitForEvent blocks the script until a matching event arrives, or the timeout expires. The return value is the accessible object of the winning event, or undef if the timeout expired. So: You see how the sample cunningly not only learns that a Notepad windows has appeared, but actually gets its Accessible Object for later use (such as to close the window).

You can omit the timeout, in which case waitForEvent waits for a matching event, which might mean waiting a very long time indeed.

The hash's entries are:

If your desires don't fit the hash mold, you can give a code-reference instead. waitForEvent returns when the code returns any non-undef. waitForEvent returns what the code returned.

 $eh->waitForEvent(sub{print Win32::ActAcc::Event::evDescribe(@_)."\n";undef}, $secs);

getEvent

You will usually want to use waitForEvent. But, just in case, there is a way to retrieve one event at a time.

getEvent retrieves an event from the event monitor, or undef if no event is ready.

The event is a blessed hash (Win32::ActAcc::Event).

clear

 $eh->clear();

Erases the backlog of events on the event monitor.

synch

synch() lets you bookmark an EventMonitor and return later to the bookmarked point.

 $eh1->synch($eh2);

``Synchronizes'' $eh1 with $eh2 by setting $eh1's event-buffer cursor to $eh2's, so that $eh1->getEvent() will return the same event as $eh2->getEvent(). synch() can move the monitor forward or backward; in other words, it can both advance and rewind. (But, when rewinding, watch out for buffer overrun. The spot you rewind to, may have been re-used since the time the event was written that you think you are rewinding to.)

isActive

 $a = $eh->isActive();

Returns a true value if the event monitor is active, a false value if it is latent.

activate

 $eh->activate(1); # activate
 $eh->activate(0); # deactivate

Activating a monitor makes it ``catch up'' with all events received so far, and makes it sensitive to future events. Activating an already-active monitor has no effect on it.

Deactivating a monitor makes it useless, until it is reactivated.

getEventCount

 my $ec = $eh->getEventCount();

Returns a cumulative total number of events caught by the event hook installed by Win32::ActAcc. (All EventMonitor objects feed from this same event hook.)

debug_spin

This debug function displays the EventMonitor's events for a certain number of seconds.

 $eh->debug_spin(60);

Win32::ActAcc::Event

An event is an object of type Win32::ActAcc::Event. It's a hash with fields as described in the API documentation:

 event
 hwnd
 idObject
 idChild
 dwmsEventTime
 $e = $eh->getEvent();
 print $$e{'event'} . "\n";

``Event'' is a constant (see EVENT Constants). You can test it like this:

 next unless Win32::ActAcc::EVENT_OBJECT_VALUECHANGE()==$$e{'event'};

getAO

 $accObj = $e->getAO();

Returns the accessible object that the event pertains to.

Active Accessibility weirdness note: getAO sometimes dies with an access-violation error. You may want to put your calls to getAO into an eval.

evDescribe

 print $e->evDescribe() . "\n";

Good for debugging - returns some information about the event.

EventConstantName

Returns the C constant name for a WinEvent number defined in WinAble.h. See EVENT Constants.

AccessibleObjectFromEvent

Obtain an ``accessible object'' from information in a WinEvent. (You may prefer to use the object-oriented $e->getAO() way instead.)

 my $accObj = AccessibleObjectFromEvent($$e{'hwnd'}, $$e{'idObject'}, $$e{'idChild'});

Event Details

Each Perl process with an active EventMonitor installs an Active Accessibility ``in-proc'' event hook that records all events in a fixed-size circular buffer.

All of the script's EventMonitor objects cursor through the process' lone circular buffer.

You will want to tightly bracket the scope of your EventMonitor objects (or deactivate them as soon as they are no longer interesting) since the event hook slows down your computer slightly and it's a pity to leave an event hook going when you don't need it.

There's no overrun indicator on the circular buffer, so try to keep your EventMonitors reasonably up-to-date lest you miss an event.

EventMonitors don't seem to pick up any WinEvents from Command Prompt windows in Windows 2000. Perhaps these windows are owned by a process that resists in-proc event hooks. Hmm.

Circular buffer size (in events) for this build of ActAcc:

5000

Tools

aaDigger.pl

aaDigger lets you navigate the hierarchy of accessible objects, rooted at the Desktop window. aaDigger has its own manpage.

When you're planning an Active Accessibility script, aaDigger helps you get your feet on the ground.

aaEvents.pl

aaEvents makes a continuous display of your system's WinEvents. When you're casting about for clues about which event your script should be keying to a real-world occurrence, aaEvents can help you make up your mind.

aaWhereAmI.pl

aaWhereAmI continuously describes the accessible object under the cursor at any given moment.

Active Accessibility weirdness note: Not all accessible objects have a place in the hierarchy that has Desktop at its root.


BUGS, LIMITATIONS, AND SHORTCOMINGS

You can't use an ``accessible object'' with Win32::OLE. Especially with Microsoft Office, it would be nice to get a ``native object model'' IDispatch* from AccessibleObjectFromWindow, and hand it off to Win32::OLE to make Office-specific OLE Automation method calls.

There's no overrun indicator on an EventMonitor. You can't tell it to ignore mouse-move events - not even redundant or superseded ones.

Win32::ActAcc probably doesn't work multi-threaded.

nav() and findDescendant() should accept the same path arguments. And the path notation should provide a dizzying combination of XPath and regular-expression features. (For XPath, see http://www.w3.org/TR/xpath.)

EventMonitors install only in-proc hooks. Maybe that's why they don't pick up any events from Command Prompt windows.

Win32::ActAcc doesn't do Unicode. If you run aaDigger.pl and point it to the Russian version of Windows Media Player, the text all comes back as question marks.


INSTALLATION

Installation from source code

 perl makefile.pl
 nmake 
 nmake install
 nmake test

Yes, you have to install it before you test it. Otherwise it can't find its DLL. Probably someone will figure out how to fix this.

Prerequisites:

Installation for ActivePerl users (PPM)

ActivePerl users can install Win32::ActAcc using PPM.

  1. Unzip the zip (Win32-ActAcc-n.n.zip). Make sure your unzip program preserved the directory tree: for example, you should see Win32-ActAcc.tar.gz in an ``x86'' subdirectory under the directory that contains ActAcc.html (the documentation).

  2. Open a command prompt window.

  3. In the command prompt, ``cd'' to the directory that contains ActAcc.html.

  4. In the command prompt, issue the following command.
     ppm install --location=. Win32-ActAcc

To check the installation, you may try aaDigger.pl. The test suite (nmake test) doesn't seem to work if you do the ppm installation.

Files Installed


COPYRIGHT

Copyright 2001, Phill Wolf.

You may use Win32::ActAcc under the terms of the Artistic License, as specified in the README file of the Perl distribution.


AUTHOR

Phill Wolf, pbwolf@cpan.org


SEE ALSO

Active Accessibility documentation. As of this writing, it is available on http://msdn.microsoft.com on the ``Libraries'' page:

 Platform SDK
  User Interface Services
   Accessibility
    Microsoft Active Accessibility

Win32::OLE

Win32::GuiTest