VBA Ribbon Access
It can hardly have escaped your notice that Word 2007 has a new interface, that the old Menus and Toolbars have been replaced by a new Ribbon. All the things that you could do with the old interface have gone, replaced by all the things you can do with the new interface; except that there isn’t anything you can do with the new interface: not in VBA, anyway. That is probably what you have been told but it isn’t entirely true.
Whilst investigating customising the legacy keyboard supportcustomising the legacy keyboard support [link to ../../Shorts/Accelerators/Accelerators.php], I stumbled over this blog post by Pranav Waghthis blog post by Pranav Wagh [link to blog at http://blogs.msdn.com/pranavwagh/archive/2008/01/21/how-to-switch-ribbon-tab-programmatically-looks-simple.aspx]. As I’m not very good with .NET, and Visual Studio and its languages (I’m trying to teach myself but it’s a slow process) I thought I’d see what could be done in VBA. What do you know, the Ribbon is accessible without having to leave home.
Microsoft® Active Accessibility® is a standard interface made available to developers of accessibility aids, software and hardware designed, to quote Microsoft, to provide additional accessibility [to computers] to individuals who have physical or cognitive difficulties, impairments, and disabilities. It has been around for a long time and, to quote Microsoft again, exposes information about most system-provided user interface elements.
There is actually a new, richer, interface – User Interface Automation – designed to replace Active Accessibility, but I don’t think Active Accessibility is likely to disappear any day soon, and it should be possible to rely on it for some time to come.
The Ribbon is, as per the above description, a system-provided user interface element, and information about it is, indeed, exposed via the Accessibility interface. Perhaps surprisingly, it is exposed to VBA, so there is no need to even leave the comfortable Word environment to see it.
The Accessibility interface offers a hierarchy of objects subordinate to the main window of the (Word) application. You can explore them all by getting a handle on that main window, but there is a short cut to the Ribbon object in the middle of the hierarchy; there is still quite a complex hierarchy of objects to navigate but you do know you are starting in the right place. The shortcut is provided by Word because, behind the scenes, the Ribbon is hiding in a familiar CommandBar object and, although you may never have had a use for it before, CommandBar objects have always offered an Accessibility interface.
So what is it that you have access to, what exactly is an Accessibility object? Simplifying somewhat, for expediency, there is one such object for each element of the User Interface, and they come in various types representing the various types of things you see on the screen. The Ribbon CommandBar Accessibility object is a ToolBar object; no real surprise there, and its actual content is displayed in the Client area of a subordinate Window. Further down the hierarchy there is a Window, the Ribbon window proper, as it were, called Ribbon , containing a Property Page, also called Ribbon, and it is within this that all the juicy detail can be found.
Amongst other children, the Ribbon Property Page contains a Page Tab List, called Ribbon Tabs, that, in turn, contains a Page Tab object for each Tab, and a Pane, called Lower Ribbon, that contains a Property Page for the current Tab; this Property Page contains a Toolbar object for each Group, which Toolbars contain the various objects you see on screen. That brief description probably sounds like gobbledegook if you are not already familiar with any aspects of it; I may return and provide more detail here, but if you can't wait, then this page on msdnthis page on msdn [link to MSDN at http://msdn.microsoft.com/en-us/library/bb404170.aspx] is as good as anywhere to start reading.
I have put together a sample template to demonstrate the technique. What started out as a simple demonstration has evolved into, almost, a ribbon-in-a-box but please remember it is just a demonstration and is not designed to be functional or useful on its own. I have tried to make the code neat and have commented it; feel free to study it at your leisure and adapt it for your own use.
It is built to be used as a global template, to be put in your Word StartUp folder, but that is not essential ffor it to work. The template has an icon on the QAT to invoke its code; it should appear at or near the end of your QAT depending on how you open it and what else you are running and has an icon showing three flags, the closest I could find to a ribbon.
I have been pleasantly surprised at the response to this page, but have been asked several times how my code can be adapted to automatically switch Ribbon Tabs when a document is opened. Rather than replying to individuals directly, I have decided to make another file available for downloading from here. This sample does not have the UserForm that the first one has, but it does have code in the Document_New and Document_Open Events, that switches to the Review tab; the tab name is hard coded, but easy to see, and change.
It has been some years since I wrote this page and my code has stood the test of time fairly well: I have not had cause to revisit it, or this page – until now, that is. I am very grateful to my correspondent, Donald LaDueDonald LaDue [link to http://ampuls.de/], who, although not the only person to bring this problem to my attention, did investigate it pretty thoroughly and help me resolve it.
The problem is caused by localisation, which, to be cynical, is Microsoft trying to give the impression that they actually care about a world outside Redmond. To be slightly fairer to them, whilst it does present enormous challenges, and does have some kinks that need ironing out, localisation is something they take very seriously.
In English, the Ribbon tabs in Word are named: Home, Insert, Page Layout, etc., If you are visually impaired you want your screen reader to read out those English words, and if you want to use the code presented here to switch to one of those tabs, you feed the name of that tab into the code. When you read, or have read to you, those words in isolation, they are meaningless, and you have to know the context, know that they are tabs on the Ribbon, to be able to understand. The graphical representation helps if you can see it, but screen readers need a textual description, which is provided by the fact they are presented in a container called “Ribbon Tabs” and this name provides the context.
This is all fine and dandy if you are English. If you are German, however, the tabs are named Start, Einfügen, Seitenlayout, uzw. As in English, it doesn’t matter what the actual words are because they can be seen and copied and read out in exactly the same way. The context, however, given by the name of a behind-the-scenes container is useless unless it, too, is localised. In German the “Ribbon Tabs” container is called “Registerkarten des Menübands”, a mealy-mouthed description, perhaps, but one that can be understood by a German-speaker.
As hinted at earlier, my code uses the existence of the Ribbon Tabs container as an aid to navigation round the hierarchy of Accessibility objects that make up the Ribbon. You will now, I hope, understand that my inadvertent use of the English name, “Ribbon Tabs”, means that my code only works on English versions of Word. Even were all the translations documented anywhere, it would be unrealistic to hard code them all and to use the appropriate one for the language interface in use, and this is but one of several such objects with localised names.
Fortunately Word does make all the necessary information available to Accessibility. Accessibility elements have a Name attribute that I have been using unconditionally, and a separate “Value” attribute. The Value only exists for those elements that need it, in particular those that have no textual description on screen but that do have localised names behind the scenes. “Ribbon Tabs” is actually the localised English name for a container called, language-independently, “Ribbon Tabs List”. The element that is wanted, in this example, is the one with a Value of “Ribbon Tabs List” regardless of its Name.
I hope this brief explanation is enough for you to be able to understand the code, which you can look at yourself. More importantly, I have updated the downloads, and I hope the code will now work for all language versions of Word.