OFFICE : Introduction aux fonctions d'accessibilité

Thierry GASPERMENT

Cet article est une introduction aux fonctions d'accessibilité.

Ces fonctions ont été développées pour faciliter l'accès à l'outil informatique aux personnes handicapées. (Détection du texte survolé par la souris, détection des alertes visuelles et sonores, ...)

Cet article s'adresse à un public développeur expérimenté.

Commentez cet article : Commentez

- Titre : OFFICE : Introduction aux fonctions d'accessibilité

- Auteur : Thierry GASPERMENT

- Parution : 25 février 2009

- Mise à jour : 12 mai 2016

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2009 Thierry GASPERMENT. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.

Sommaire

- I. Introduction

- II. Premières découvertes

- III. Comment utiliser ces fonctions d'accessibilité dans Office?

- IV. Les propriétés et méthodes de l'objet IAccessible

- V. Utilisation directe des fonctions masquées dans Access

- V-A. Première approche

- V-B. Elément survolé dans une liste

- V-C. Conclusion

- VI. Utilisation de l'API : librairie oleacc.dll

- VI-A. Le module de classe clAccessibility

- VI-B. Fonctionnement du module clAccessibility

- VI-C. Exemple 1 : afficher l'élément situé sous le curseur de la souris

- VI-D. Exemple 2 : Le bouton Démarrer de Windows.

- VI-D-1. Exemple 2-a : Cliquer sur le bouton lorsqu'on le survole.

- VI-D-2. Exemple 2-b : Cliquer sur le bouton à la demande.

- VI-D-3. Exemple 2-c : Changer le texte du bouton Démarrer.

- VI-E. Exemple 3 : Lister le contenu de la zone de notification.

- VI-F. Exemple 4 : Le ruban Office 2007.

- VI-F-1. Exemple 4-a : Ouvrir le menu Office.

- VI-F-2. Exemple 4-b : Lister les onglets du ruban.

- VI-F-3. Exemple 4-c : Connaître l'onglet actif.

- VI-F-4. Exemple 4-d : Activer un onglet.

- VI-G. Conclusion

- VII. Remerciements

I - Introduction

Les fonctions d'accessibilité sont une interface de programmation développée par Microsoft.
En anglais : MSAA pour MicroSoft Active Accessibility.

L'interface est livrée sous forme d'API dans une librairie dll (oleacc.dll).

- La version 2.0 est livrée à partir de Windows XP.

- La version 3.0 est livrée à partir de Windows 7.

La version redistribuable 2.0 peut être téléchargée si nécessaire ici ou ici pour les versions de Window antérieures (Windows 98, Windows ME, Windows NT…).

(Une version antérieure est peut-être déjà installée par défaut et peut s'avérer suffisante).

Le tableau récapitulatif des versions est disponible ici : Supported Platforms

L'évolution des fonctions d'accessibilité dans Windows Vista s'appelle Microsoft UI Automation.

Ces fonctions sont utilisables dans toute application qui a implémenté cette interface :

- Office (Access, Excel, ...)

- Internet Explorer

- Le bureau de Windows

- L'explorateur de fichier Windows

- ....

Même si l'application n'est pas spécifiquement programmée pour, on pourra utiliser les fonctions d'accessibilité sur ses contrôles standards.

Chaque fenêtre ou contrôle est potentiellement un objet d'accessibilité.

On peut alors lui appliquer des fonctions d'accessibilité pour connaître :

- sa position (en pixel sur l'écran)

- son nom

- sa valeur

- son rôle (élément de liste, onglet, fenêtre, ...)

- son état (coché, sélectionné, ...)

- son parent

- ses enfants (les contrôles qu'il contient)

Et on peut également exécuter son action par défaut.

Si on peut lire beaucoup d'informations, il n'est pas possible d'agir sur ces objets avec les fonctions d'accessibilité (mise à part l'action par défaut).

Par contre on peut récupérer l'identifiant (handle) de la fenêtre à laquelle correspond un objet pour lui envoyer des messages.

II - Premières découvertes

La page d'accueil de la librairie MSDN est ici : Microsoft Active Accessibility

Pour bien débuter et comprendre ce que sont ces fameux objets d'accessibilité, le plus simple est d'utiliser les outils du SDK.

Ces outils sont disponibles dans le SDK Windows.

Ce SDK étant très volumineux, si vous ne l'avez pas déjà il peut être préférable de télécharger ces outils ici : gui-inspect-tool

Dans ce SDK vous avez 3 programmes intéressants :

- Accessible Explorer (AccExplorer32.exe)

- Inspect Objects (Inspect32.exe)

- Accessible Event Watcher (AccEvent32.exe)

Accessible Explorer permet de visualiser l'arborescence des objets d'une fenêtre.

Lancez le programme, cliquez sur la cible dans le menu :

Tirez la cible vers un formulaire Access et relâcher.

On visualise tous les objets d'accessibilité de ce formulaire.

(Cliquez sur Object => Highlight dans le menu pour visualiser l'objet sélectionné dans la liste)

Inspect Objects affiche les informations de l'objet qui se trouve sous le curseur de la souris.

Lancez le programme et essayez de déplacer la souris sur diverses applications.

Accessible Event Watcher est un programme qui permet de visualiser les événements qui ont lieu.

Ces trois programmes sont très utiles lors du développement pour nous aider à repérer les différents objets et leur comportement.

Vous trouverez également en téléchargement un fichier de documentation MSAAv2.doc (en anglais) qui recense les fonctions et constantes utilisées.

III - Comment utiliser ces fonctions d'accessibilité dans Office?

L'ensemble des fonctions d'accessibilité est regroupé dans la librairie oleacc.dll.

Il est nécessaire de déclarer les fonctions et variables pour y avoir accès.

Nous utiliserons dans la suite de l'article un module de classe qui encapsule ces fonctions pour plus de facilité.

Cependant, certains objets présentent une interface IAccessible qui permet de directement faire appel à certaines de ces fonctions.

Attention : ces fonctions ne sont pas documentées et doivent donc être utilisées avec prudence.

Voici une liste de ces objets (correspond à Access 2003) :

Librairie

Objet

Remarques

Office

CommandBar

Barre de menu

Office

CommandBarButton

Bouton dans un menu

Office

CommandBarComboBox

Liste déroulante dans un menu

Office

CommandBarControl

Contrôle dans un menu

Office

CommandBarPopup

Barre de menu contextuel

Access

BoundObjectFrame

Cadre d'objet dépendant

Access

CheckBox

Case à cocher

Access

ComboBox

Zone de liste déroulante

Access

CommandButton

Bouton de commande

Access

CustomControl

Contrôle personnalisé

Access

Form

Formulaire

Access

Label

Etiquette

Access

ListBox

Zone de liste

Access

OptionButton

Bouton d'option

Access

Page

Page d'onglet

Access

OptionGroup

Groupe d'options

Access

SubForm

Sous-formulaire

Access

TabControl

Contrôle à onglets

Access

TextBox

Zone de texte

Access

ToggleButton

Bouton bascule

Pour voir les fonctions non documentées :

- affichez l'explorateur d'objets dans l'éditeur VBA.

- click droit dans l'explorateur d'objets puis sélectionnez Afficher les membres masqués.

Pour les objets possédant une interface IAccessible, on note alors une série de fonctions commençant par acc.

IV - Les propriétés et méthodes de l'objet IAccessible

Téléchargez la documentation des fonctions et des propriétés (anglais)

Consultez la librairie MSDN (anglais)

Méthode ou propriété

Fonction

Remarques

accName

Nom de l'objet

- Le nom d'un contrôle est le texte de l'étiquette qui lui est attachée ou le nom du contrôle s'il n'a pas d'étiquette
- Le nom d'une fenêtre est son titre

accDefaultAction

Action par défaut

C'est un texte : Press, Ouvrir

accDoDefaultAction

Déclenche l'action par défaut

accRole

Rôle de l'objet

Utiliser l'API GetRoleText pour récupérer le texte correspondant

accState

Etat de l'objet

Utiliser l'API GetStateText pour récupérer le texte correspondant

accParent

Objet parent

L'objet parent d'un contrôle par exemple est le client du formulaire

accDescription

Description de l'objet

accKeyboardShortcut

Raccourci clavier de l'objet (pour les entrées de menu par exemple)

accChildCount

Nombre de sous-objets de l'objet

accFocus

Sous-objet qui a le focus

accLocation

Position de l'objet sur l'écran

Cette position est donnée en pixel.

accHitTest

Sous-objet sous le curseur de la souris

accSelection

Liste des objets sélectionnés

accSelect

Modifie la sélection

accHelp

Texte d'aide

accHelpTopic

Fichier d'aide correspondant

V - Utilisation directe des fonctions masquées dans Access

V-A - Première approche

Créez sur un nouveau formulaire une zone de texte txtTexte et un bouton btnBouton.

Sur click sur le bouton, ajouter ce code :

Sur click sur le bouton

Private Sub btnBouton_Click()
MsgBox Me.txtTexte.accName(ByVal 0&)
End Sub

Le paramètre ByVal 0& est important : il précise que la fonction s'applique sur l'objet et non pas un de ses sous-objet.

Pour information : ce paramètre correspond à la constante CHILDID_SELF.

Ouvrez le formulaire et cliquez sur le bouton.

Le message qui s'affiche contient le texte de l'étiquette rattachée à la zone de texte.

S'il n'y a pas d'étiquette, le message affiche le nom du contrôle.

Ajoutons l'affichage de la valeur de la zone de texte :

Sur click sur le bouton

Private Sub btnBouton_Click()
MsgBox Me.txtTexte.accName(ByVal 0&) & " :" & Me.txtTexte.accValue(ByVal 0&)
End Sub

Si la zone de texte est vide, une erreur est levée (sur certaines versions), sinon son contenu s'affiche.

V-B - Elément survolé dans une liste

Nous allons aller un peu loin (et plus utile) en recherchant l'élément survolé par la souris sur une zone de liste.

Créez sur un nouveau formulaire une zone de liste lstListe contenant quelques éléments.

Ajoutez une zone de texte txtTexte.

Pour connaître la position de la souris, ajoutez ces déclarations en en-tête de module du formulaire.

API pour position de la souris

Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As PointAPI) As Long
Private Type PointAPI
X As Long
Y As Long
End Type

Sur souris déplacée sur la liste, ajouter ce code :

Sur souris déplacée sur la liste

Private Sub lstListe_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim lPt As PointAPI
Dim lElement As Variant
' Position de la souris
GetCursorPos lPt
' Elément survolé
lElement = Me.lstListe.accHitTest(lPt.X, lPt.Y)
' Inscrit le numéro de l'élément survolé dans la zone de texte
Me.txtTexte.Value = lElement
End Sub

Ouvrez le formulaire et déplacer la souris sur la liste.

Le numéro de l'élément survolé s'affiche dans la zone de texte.

Notez que ce numéro débute à 1, contrairement à la propriété ListIndex de la zone de liste qui débute à 0.

On note également que lorsqu'on déplace la souris sur la liste en dessous du dernier élément, la fonction accHitTest renvoit 1 alors qu'on ne survole aucun élément.

Pour corriger ce problème, on va déterminer la position de l'élément avec la fonction accLocation pour la comparer à la position de la souris.

Sur souris déplacée sur la liste

Private Sub lstListe_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim lPt As PointAPI
Dim lElement As Variant
Dim lLeft As Long, lTop As Long, lWidth As Long, lHeight As Long
' Position de la souris
GetCursorPos lPt
' Element survolé
lElement = Me.lstListe.accHitTest(lPt.X, lPt.Y)
' Position de l'élément
Me.lstListe.accLocation lLeft, lTop, lWidth, lHeight, lElement
' Vérifie qu'on survole effectivement l'élement
If lPt.X < lLeft Or lPt.X > lLeft + lWidth Or lPt.Y < lTop Or lPt.Y > lTop + lWidth Then
lElement = 0
End If
' Inscris le numéro de l'élément survolé dans la zone de texte
Me.txtTexte.Value = lElement
End Sub

On passe l'élément en paramètre de la fonction accLocation pour connaître sa position à l'écran.

Si on voulait lire la position de la liste, on utiliserait le paramètre Byval 0&

V-C - Conclusion

Nous n'avons pas développé ici toutes les possibilités de ces fonctions masquées.

Même si elles peuvent s'avérer utiles, elles sont toutefois limitées.

L'utilisation des API offre beaucoup plus de possibilités.

VI - Utilisation de l'API : librairie oleacc.dll

VI-A - Le module de classe clAccessibility

Pour faciliter l'utilisation des fonctions et constantes d'accessibilité, nous allons utiliser un module de classe spécifique.

Ce module se nomme clAccessibility.

Télécharger le module de classe au format texte

Une fois téléchargé et décompressé, importez le fichier clAccessibility.cls dans votre projet.

Dans le menu : Fichier => Importer un fichier ... (ou glisser-déposer le fichier dans le projet).

Le module de classe est nommé clAccessibility.

Ce module utilise un objet IAccessible que l'on peut trouver dans la librairie Microsoft Office XX Object Library.

Le XX correspond à la version d'Office installée.

Ajoutez donc une référence à cette librairie : Outils => Références ....

VI-B - Fonctionnement du module clAccessibility

Consultez la documentation des fonctions et des propriétés de ce module.

Pour utiliser ce module, il faut d'abord créer un objet de type clAccessibility.

Objet clAccessibility

Dim oAcc As ClAccessibility
Set oAcc = New ClAccessibility

Ensuite, définissez l'objet avec une des fonctions SetAccObjFrom*.

Par exemple, pour un formulaire Access :

Défini l'objet Formulaire

oAcc.SetAccObjFromObject Me

Les fonctions et propriétés sont alors accessibles.

Par exemple, pour parcourir les éléments du formulaire et afficher leur nom et rôle :

Parcourt les éléments du formulaire

Private Sub Commande0_Click()
Dim oAcc As ClAccessibility
Dim lCpt As Long
Dim ltexte As String
' Nouvel objet
Set oAcc = New ClAccessibility
' Définit le formulaire en objet
oAcc.SetAccObjFromObject Me
' Boucle sur les sous-éléments
For lCpt = 1 To oAcc.Childcount
' Ajoute au texte le nom et le rôle du sous-élément
ltexte = ltexte & vbCrLf & oAcc.GetChild(lCpt).Name & " : " & oAcc.GetChild(lCpt).RoleText
Next
' Affiche le texte dans une boîte de message
MsgBox ltexte
End Sub

VI-C - Exemple 1 : afficher l'élément situé sous le curseur de la souris

Cet exemple est réalisé avec Excel.

Dans un nouveau module VBA, ajoutez une fonction qui va lire les informations de l'objet sous le curseur de la souris :

Fonction de lecture de l'objet sous la souris

Function DisplayElementUnderMouse()
Dim oAcc As ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
' Récupère l'objet sous le curseur de la souris
' Inscrit le nom et le rôle de l'objet sur la première cellule de la première feuille
If oAcc.SetAccObjFromPosition Then
Sheets(1).Range("A1").Value = oAcc.Name & " : " & oAcc.RoleText
Else
Sheets(1).Range("A1").Value = ""
End If
End Function

Cette fonction récupère l'objet sous le curseur de la souris à l'aide de la fonction SetAccObjFromPosition.

Ensuite elle met à jour la première cellule de la première feuille avec les informations de l'objet récupéré.

Pour que cette fonction s'exécute en boucle on va utiliser la procédure OnTime.

Afin de pouvoir arrêter cette boucle, on utilise une variable gStop.

Code complet du module

Option Explicit

' Variable pour stopper le traitement
Private gStop As Boolean

' Fonction de lecture de l'objet sous la souris
Function DisplayElementUnderMouse()
Dim oAcc As ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
' Récupère l'objet sous le curseur de la souris
' Inscrit le nom et le rôle de l'objet sur la première cellule de la première feuille
If oAcc.SetAccObjFromPosition Then
Sheets(1).Range("A1").Value = oAcc.Name & " : " & oAcc.RoleText
Else
Sheets(1).Range("A1").Value = ""
End If
' Relance la fonction dans une seconde sauf si stop demandé
If Not gStop Then Application.OnTime DateAdd("s", 1, Now), "DisplayElementUnderMouse"
End Function

' Lance l'affichage
Sub StartDisplay()
gStop = False
DisplayElementUnderMouse
End Sub

' Arrête l'affichage
Sub StopDisplay()
gStop = True
End Sub

Pour faciliter l'exécution des fonctions, créer sur la première feuille du classeur deux formes rectangulaires auxquelles vous affectez les procédures StartDisplay et StopDisplay.

Cliquez sur le premier bouton pour démarrer l'exécution.

La cellule en haut à gauche est actualisée toute les secondes avec les informations de l'élément situé sous le curseur de la souris.

Cliquez sur le deuxième bouton pour arrêter l'exécution.

Sur l'image, le curseur est positionné sur le menu Insertion d'Excel.

Il est cependant possible d'accéder à des objets n'appartenant pas à l'application Excel.

Nous allons le voir dans l'exemple suivant.

VI-D - Exemple 2 : Le bouton Démarrer de Windows.

VI-D-1 - Exemple 2-a : Cliquer sur le bouton lorsqu'on le survole.

Cet exemple est réalisé avec Excel, à la suite du code précédent.

Si vous déplacez le curseur de la souris sur le menu démarrer, le code précédent nous indique : Démarrer : bouton poussoir.

Note : cela est identique avec les versions de Windows plus récentes (Windows 10 par exemple ).

On peut voir ces mêmes informations également à l'aide du programme inspect32.exe (voir le lien de téléchargement en introduction).

Pour cliquer sur le menu Démarrer de Windows lorsqu'on le survol, ajoutez ce code avant la relance de la fonction avec onTime.

Clique sur le bouton démarrer si on le survol

' Si le curseur est sur un bouton poussoir de nom "Démarrer"
If oAcc.Role = ROLE_SYSTEM_PUSHBUTTON And oAcc.Name = "Démarrer" Then
' Cliquer sur ce bouton
oAcc.DoDefaultAction
End If

Lorsqu'on survole le bouton Démarrer, le programme clique dessus automatiquement.

VI-D-2 - Exemple 2-b : Cliquer sur le bouton à la demande.

Cet exemple est réalisé avec Excel.

On a vu précédemment comment cliquer sur un bouton à l'aide de la fonction DoDefaultAction.

L'objet bouton était détecté lors du survol de la souris.

Comment faire pour retrouver ce bouton si on ne le survole pas ?

L'objet de plus haut niveau est le bureau Windows : à partir de lui on peut retrouver n'importe quel objet.

On peut donc écrire une petite fonction qui définit le bureau comme premier objet, et qui cherche ensuite le bouton Démarrer de manière récursive à l'aide de la fonction FindChild.

Clique sur le bouton démarrer

Function ClickStartupMenu()
Dim oAcc As ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
oAcc.SetAccObjFromDesktop OBJID_WINDOW
Set oAcc = oAcc.FindChild("Démarrer", ROLE_SYSTEM_PUSHBUTTON, , , , True)
If Not oAcc Is Nothing Then
oAcc.DoDefaultAction
End If
End Function

Si vous exécutez la fonction, le programme clique sur le bouton Démarrer.

C'est la méthode la plus simple mais certainement pas la plus efficace.

Première remarque : Est-on certain qu'il n'existe qu'un seul bouton nommé "Démarrer"?

Deuxième remarque : Il existe énormément d'objet d'accessibilité sur le bureau; la recherche peut prendre un certain temps s'il n'est pas situé vers le haut de l'arborescence.

Nous allons donc modifier la fonction pour ne plus utiliser l'option de récursivité de la recherche.

Il faut alors connaître exactement les parents de l'objet recherché.

Pour nous aider, on peut utiliser les programmes inspect32.exe ou AccExplorer32.exe.

On note les parents du bouton Démarrer et leurs informations utiles :

Nom

Rôle

Classe de fenêtre

Démarrer

Bouton poussoir

Button

Démarrer

Fenêtre

Button

Client

Shell_TrayWnd

Fenêtre

Shell_TrayWnd

Bureau

Client

#32769

Bureau

Fenêtre

#32769

Il est possible que certains objets n'aient pas de nom.

On peut alors également rechercher les objets à l'aide de la classe de fenêtre, ce que nous allons faire pour la barre des tâches (Shell_TrayWnd).

Le premier élément est l'élément recherché : un bouton poussoir de nom "Démarrer".

Le dernier élément est le bureau que l'on peut récupérer à l'aide de la fonction SetAccObjFromDesktop.

On démarre en fait de l'avant-dernier élément car la fonction nous permet de préciser qu'on veut récupérer l'objet client.

Clique sur le bouton démarrer

Function ClickStartupMenu()
Dim oAcc As ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
' Objet Bureau : client
oAcc.SetAccObjFromDesktop OBJID_CLIENT
' Barre des tâches : fenêtre
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_WINDOW, , "Shell_TrayWnd")
' Barre des tâches : client
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT, , "Shell_TrayWnd")
' Menu démarrer : fenêtre
Set oAcc = oAcc.FindChild("Démarrer", ROLE_SYSTEM_WINDOW)
' Menu démarrer : bouton poussoir
Set oAcc = oAcc.FindChild("Démarrer", ROLE_SYSTEM_PUSHBUTTON)
' Si on a trouver le bouton
If Not oAcc Is Nothing Then
' On clique dessus
oAcc.DoDefaultAction
End If
End Function

Exécutez la fonction pour ouvrir le menu démarrer.

Les fonctions FindChild ne sont pas récursives dans cet exemple.

On maîtrise la descente niveau par niveau jusqu'à l'objet recherché.

On a vu dans cet exemple un principe récurrent qui veut qu'il y a presque toujours une fenêtre contenant un client.

La fenêtre contient également la barre de titre, le menu système, les barres de défilements, ...

Le client contient notamment les contrôles (listes, boutons, ...).

VI-D-3 - Exemple 2-c : Changer le texte du bouton Démarrer.

Cet exemple est réalisé avec Excel, à la suite du code précédent.

Cet exemple ne fonctionne qu'avec les anciennes versions de Windows où un texte était affiché sur le menu démarrer.

Nous allons modifier la fonction précédente ClickStartupMenu pour changer le texte du bouton Démarrer.

Le texte "Démarrer" est contenu dans la propriété name de l'objet.

Cette propriété est en écriture mais n'a aucun effet si on cherche à la modifier.

Même si cette propriété est bien définie en écriture pour l'objet IAccessible, elle n'est pas gérée en écriture par la plupart des objets. (C'est également le cas de la propriété value)

Par contre on peut modifier le texte de la fenêtre grâce à la fonction WindowSetText.

C'est fonction appelle l'API SetWindowText qui modifie le texte d'une fenêtre.

"Fenêtre" est à prendre au sens large : un bouton peut également être une fenêtre.

Change le texte du bouton Démarrer

Function ChangeStartupMenu(pText As String)
Dim oAcc As ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
' Objet Bureau : client
oAcc.SetAccObjFromDesktop OBJID_CLIENT
' Barre des tâches : fenêtre
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_WINDOW, , "Shell_TrayWnd")
' Barre des tâches : client
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT, , "Shell_TrayWnd")
' Menu démarrer : fenêtre
Set oAcc = oAcc.FindChild("Démarrer", ROLE_SYSTEM_WINDOW)
' Menu démarrer : bouton poussoir
Set oAcc = oAcc.FindChild("Démarrer", ROLE_SYSTEM_PUSHBUTTON)
' Si on a trouver le bouton
If Not oAcc Is Nothing Then
' On change le texte
oAcc.WindowSetText , pText
End If
End Function

Dans la fenêtre d'exécution :

Change le texte du bouton Démarrer

ChangeStartupMenu "Coucou"

Le texte du bouton est modifié :

VI-E - Exemple 3 : Lister le contenu de la zone de notification.

On va dans cet exemple lister le contenu de la zone de notification (les icônes à droite de la barre des tâches).

Pour changer, cet exemple est réalisé avec Word et Windows 7.

On note (à l'aide des programmes inspect32.exe ou AccExplorer32.exe) les parents d'une des icônes et leurs informations utiles :

Nom

Rôle

Classe de fenêtre

Volume

Bouton poussoir

ToolbarWindow32

Zone de notification

Barre d'outils

ToolbarWindow32

Zone de notification

Fenêtre

ToolbarWindow32

Client

SysPager

Fenêtre

SysPager

Client

TrayNotifyWnd

Fenêtre

TrayNotifyWnd

Client

Shell_TrayWnd

Fenêtre

Shell_TrayWnd

Bureau

Client

#32769

Bureau

Fenêtre

#32769

On navigue alors d'objet en objet jusqu'à trouver la barre d'outils contenant les icônes.

Puis on parcourt les sous-éléments et, si l'objet est visible, on ajoute au texte le nom et le rôle du sous-élément.

Liste des icônes visibles dans la zone de notification

Function ListSystray()
Dim oAcc As ClAccessibility
Dim lcpt As Long
Dim ltexte As String
' Nouvel objet
Set oAcc = New ClAccessibility
' Nouvel objet
Set oAcc = New ClAccessibility
' Objet Bureau : client
oAcc.SetAccObjFromDesktop OBJID_CLIENT
' Barre des tâches : fenêtre
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_WINDOW, , "Shell_TrayWnd")
' Barre des tâches : client
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT, , "Shell_TrayWnd")
' Zone de notification : fenêtre
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_WINDOW, , "TrayNotifyWnd")
' Zone de notification : client
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT, , "TrayNotifyWnd")
' SysPager : fenêtre
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_WINDOW, , "SysPager")
' SysPager : client
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT, , "SysPager")
' Barre d'outils : fenêtre
Set oAcc = oAcc.FindChild("Zone de notification", ROLE_SYSTEM_WINDOW, , "ToolbarWindow32")
' Barre d'outils : client
Set oAcc = oAcc.FindChild("Zone de notification", ROLE_SYSTEM_TOOLBAR, , "ToolbarWindow32")
' Boucle sur les sous-éléments
For lcpt = 1 To oAcc.Childcount
' Seulement si l'objet est visible
If (oAcc.GetChild(lcpt).State And STATE_SYSTEM_INVISIBLE) <> STATE_SYSTEM_INVISIBLE Then
' Ajoute au texte le nom et le rôle du sous-élément
ltexte = ltexte & vbCrLf & oAcc.GetChild(lcpt).Name & " : " & oAcc.GetChild(lcpt).RoleText
End If
Next
' Affiche le texte sur le document
ThisDocument.Content.Font.Size = 6
ThisDocument.Content.Text = ltexte
End Function

Exécutez la fonction pour lister les icônes visibles :

Connexion réseau sans fil PCMCIA (Fast3302_5fc4)
Vitesse : 54,0 Mbits/s
Force du signal : Excellent
État : Connecté : bouton poussoir
Retirer le périphérique en toute sécurité : bouton poussoir
Windows Live Messenger (Hors ligne) : bouton poussoir
Volume : bouton poussoir
Source d'alimentation actuelle : Alimentation secteur
Autonomie batterie : 100%
Profil : Pleine puissance : bouton
Connexion réseau sans fil
Connexion sans fil non disponible
Son virtuel TOSHIBA : Activé : bouton poussoir
Intel(R) Graphics Media Accelerator Driver for Mobile : bouton poussoir
Application Modem On Hold V.92 : bouton poussoir

VI-F - Exemple 4 : Le ruban Office 2007.

Ces exemples sont réalisés avec Access, mais le code est similaire pour toute application ayant un ruban.

Les objets d'accessibilité du ruban sont décrits dans ce document (en anglais) :
Working with Active Accessibility in the 2007 Office Fluent User Interface

Pensez également à utiliser le programme AccExplorer32.exe pour voir l'arborescence des éléments du ruban.

Voici l'arborescence du ruban vu par le programme AccExplorer32.exe :

Ruban 2007

Ruban 2010

Pour atteindre le ruban, on utilisera l'objet CommandBars. Ensuite on recherche l'objet de valeur Ribbon et de rôle ROLE_SYSTEM_PROPERTYPAGE.

Code pour accéder à l'objet Ruban

Dim oAcc As ClAccessibility
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)

On obtient alors l'objet racine qui nous permettra d'accéder aux divers éléments du ruban.

VI-F-1 - Exemple 4-a : Ouvrir le menu Office.

En version Office 2007, le menu Office a un rôle égal à ROLE_SYSTEM_BUTTONDROPDOWNGRID.

A partir de la version 2010, le menu Office est remplacé par un bouton poussoir simple « FICHIER » ; ce chapitre ne fonctionne donc que sur Office 2007.

Pour appuyer sur ce bouton, il suffit d'exécuter son action par défaut (DoDefaultAction).

Appuye sur le bouton Office

Function OpenOfficeMenu()
Dim oAcc As ClAccessibility
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Menu Office
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_BUTTONDROPDOWNGRID)
' Appuie sur le bouton du menu Office
oAcc.DoDefaultAction
End Function

Si on exécute la fonction, le menu s'ouvre ou se ferme.

Si on souhaite ne pas fermer le menu, il faut vérifier s'il est déjà ouvert en testant la propriété state.

Appuye sur le bouton Office sauf si le menu est déjà ouvert

Function OpenOfficeMenu()
Dim oAcc As ClAccessibility
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Menu Office
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_BUTTONDROPDOWNGRID)
' Si le bouton n'est pas déjà pressé
If (oAcc.State And STATE_SYSTEM_PRESSED) <> STATE_SYSTEM_PRESSED Then
' Ouvre le menu Office
oAcc.DoDefaultAction
End If
End Function

VI-F-2 - Exemple 4-b : Lister les onglets du ruban.

Les onglets sont listés dans l'objet de rôle ROLE_SYSTEM_PAGETABLIST (en fait dans son client).

Remarque : les onglets contextuels sont des objets de rôle ROLE_SYSTEM_PAGETAB inclus dans un objet de rôle ROLE_SYSTEM_GROUPING.

Dans l'exemple ci-dessous, on ne les gère pas.

Affiche la liste des onglets

Function ListRibbonTabs()
Dim oAcc As ClAccessibility
Dim oTab As ClAccessibility
Dim lCpt As Long
Dim lText As String
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Liste des onglets
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PAGETABLIST)
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT)
' Parcourt les sous-éléments
For lCpt = 1 To oAcc.Childcount
' Sous-élement
Set oTab = oAcc.GetChild(lCpt)
' Si le sous-élément est un onglet
If oTab.Role = ROLE_SYSTEM_PAGETAB Then
' Ajoute son nom et s'il est visible ou non
lText = lText & vbCrLf & oTab.Name & " :" & IIf((oTab.State And STATE_SYSTEM_FOCUSABLE) = STATE_SYSTEM_FOCUSABLE, "visible", "invisible")
End If
Next
' Affiche le texte
MsgBox lText
End Function

Ce code affiche la liste des onglets dans une boîte de message.

VI-F-3 - Exemple 4-c : Connaître l'onglet actif.

L'objet représentant l'onglet actif est situé dans le ruban inférieur (valeur Lower Ribbon de rôle ROLE_SYSTEM_PANE).

Ce ruban inférieur contient d'abord un client (ROLE_SYSTEM_CLIENT) puis l'onglet actif de rôle ROLE_SYSTEM_PROPERTYPAGE.

Créez un nouveau formulaire contenant une zone de texte nommé txtTexte.

Cette zone de texte affichera le nom de l'onglet courant.

Dans l'événement Sur minuterie du formulaire, on récupère l'objet représentant l'onglet courant et on inscrit le nom de cet onglet dans la zone de texte.

Affiche l'onglet actif

Private Sub Form_Timer()
Dim oAcc As ClAccessibility
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Ruban inférieur
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PANE, "Lower Ribbon")
' Client sans nom
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT)
' Onglet actif
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE)
' Inscrit le nom de l'onglet actif dans la zone de texte
If Not oAcc Is Nothing Then Me.txtTexte.Value = oAcc.Name
End Sub

N'oublions pas de préciser un intervalle de minuterie dans les propriétés du formulaire.

Afficher le formulaire et naviguer dans les onglets pour tester le code.

VI-F-4 - Exemple 4-d : Activer un onglet.

Dans cet exemple nous souhaitons activer un onglet.

Cela peut être utile pour afficher un onglet spécifique en fonction du contrôle actif.

Activer un onglet est simple : il suffit d'exécuter son action par défaut (DoDefaultAction).

Créez un nouveau formulaire dans lequel vous placez une zone de liste nommée lstOnglets.

La propriété Origine source de cette liste doit être égale à Liste valeurs.

On remplit la liste des onglets au démarrage du formulaire.

Le code est similaire à celui vu dans l'exemple 4-b : Lister les onglets du ruban.

Remplissage de la liste à l'ouverture du formulaire

Private Sub Form_Load()
Dim oAcc As ClAccessibility
Dim oTab As ClAccessibility
Dim lCpt As Long
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Liste des onglets
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PAGETABLIST)
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT)
' Initialise la liste
Me.lstOnglets.RowSource = ""
' Parcourt les sous-éléments
For lCpt = 1 To oAcc.Childcount
' Sous-élement
Set oTab = oAcc.GetChild(lCpt)
' Si le sous-élément est un onglet
If oTab.Role = ROLE_SYSTEM_PAGETAB Then
' Ajoute son nom à la liste
If Not Me.lstOnglets.RowSource = "" Then Me.lstOnglets.RowSource = Me.lstOnglets.RowSource & ";"
Me.lstOnglets.RowSource = Me.lstOnglets.RowSource & oTab.Name
End If
Next
End Sub

Ensuite lorsqu'on choisit un onglet dans la liste, on active l'onglet correspondant dans le ruban.

Choix dans la liste, active l'onglet

Private Sub lstOnglets_AfterUpdate()
Dim oAcc As ClAccessibility
Dim oTab As ClAccessibility
Dim lCpt As Long
Set oAcc = New ClAccessibility
' Objet ruban
oAcc.SetAccObjFromObject CommandBars("ribbon")
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PROPERTYPAGE, "Ribbon", , , True)
' Liste des onglets
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_PAGETABLIST)
Set oAcc = oAcc.FindChild(, ROLE_SYSTEM_CLIENT)
' Parcourt les sous-éléments
For lCpt = 1 To oAcc.Childcount
' Sous-élement
Set oTab = oAcc.GetChild(lCpt)
' Si le sous-élément est l'onglet sélectionné dans la liste
If oTab.Role = ROLE_SYSTEM_PAGETAB And oTab.Name = Nz(Me.lstOnglets.Value) Then
' Active l'onglet
oTab.DoDefaultAction
End If
Next
End Sub

Choisissez un élément de la liste, l'onglet correspondant s'affiche.

Remarque : on n'a pas filtré les onglets invisibles.

Si vous cliquez sur une entrée de liste correspondant à un onglet invisible, rien ne se produit.

VI-G - Conclusion

Les possibilités des fonctions d'accessibilité sont nombreuses.

Parfois on peut utiliser conjointement ces fonctions d'accessibilité et les fonctions de l'API Windows pour encore plus de possibilités.

Dernière remarque : il ne faut pas oublier d'utiliser les outils du SDK pour analyser les objets.

VII - Remerciements

Merci à l'équipe Office pour ses tests et relectures.

Merci à developpez.com pour son hébergement de qualité.