The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

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.

  • You obtain accessible objects and event streams using the Active Accessibility API, via Win32::ActAcc.

  • You manipulate an accessible object using IAccessible, via Win32::AO.

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 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 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_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.

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:

  • you call "activate".

  • you call a method (like click or "menuPick") that activates the monitor so you can capture the results of the click.

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:

  • event: an event constant (remember the parentheses--see sample above). See "EVENT Constants".

  • name (optional): a regexp or string to match the name of the accessible object of the event. If it's a string, it must match exactly--case matters and it must match the entire name.

  • role (optional): a role constant that must match the accessible object of the event, e.g., Win32::ActAcc::ROLE_SYSTEM_WINDOW(). See "ROLE Constants".

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:

  • You may need Visual C++ 6.0 SP 4. The C/C++ part of Win32::ActAcc might not be portable to other compilers.

  • You need the July 2000 "Platform SDK". Earlier versions of the Active Accessibility SDK could give problems compiling.

  • The test suite requires Notepad.exe on the path. Also, it requires Win32::GuiTest.

  • The Eliza-AOLInstantMessenger sample requires up-to-date HTML parsing modules. It will tell you if yours are missing or out-of-date.

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

  • In bin: aaDigger.bat and aaDigger.pl, aaEvents.bat and aaEvents.pl, aaWhereAmI.bat and aaWhereAmI.pl

  • In site\lib\Win32: aaDigger.pl, aaEvents.pl, aaWhereAmI.pl, ActAcc.pm, ActAcc.pod

  • In site\lib\auto\Win32\ActAcc: ActAcc.dll, ActAccEM.dll

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

7 POD Errors

The following errors were encountered while parsing the POD:

Around line 70:

=back doesn't take any parameters, but you said =back 4

Around line 97:

=back doesn't take any parameters, but you said =back 4

Around line 593:

=back doesn't take any parameters, but you said =back 4

Around line 640:

=back doesn't take any parameters, but you said =back 4

Around line 869:

=back doesn't take any parameters, but you said =back 4

Around line 898:

=back doesn't take any parameters, but you said =back 4

Around line 920:

=back doesn't take any parameters, but you said =back 4