OFFICE : Introduction aux fonctions d'accessibilité

Image non disponible

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 : 7 commentaires Donner une note à l'article (4.5) 

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 :Image non disponible

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

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

Image non disponible

(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.
Image non disponible

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

Image non disponible

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
Sélectionnez
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
Sélectionnez
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.

Image non disponible

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
Sélectionnez
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
Sélectionnez
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.

Image non disponible

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
Sélectionnez
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 ....

Image non disponible

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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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
Image non disponible

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
Sélectionnez
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
Sélectionnez
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.

Image non disponible

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.

Image non disponible

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

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
Sélectionnez
' 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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
ChangeStartupMenu "Coucou"      

Le texte du bouton est modifié :

Image non disponible

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
Sélectionnez
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
Image non disponible
Image non disponible

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
Sélectionnez
    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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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.

Image non disponible

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
Sélectionnez
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.

Image non disponible

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
Sélectionnez
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
Sélectionnez
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.

Image non disponible

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

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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.