Texel
DirectX | Index | Contact

La souris



Téléchargez un code source pour ce tutorial ICI.

Pour utiliser la souris avec Direct Input, il faut passé par ces étapes:

1.Créer un objet DirectInput :Cet objet est l'interface principale qui permet d'utiliser une ou plusieurs unités d'entrées.
2.Créer un objet DirectInputDevice : Cet objet représente une unité d'entrée. Si votre programme utilise le clavier et la souris, vous devez créer deux de ces objets (un pour le clavier et un pour la souris).
3.Définir un format de donné pour l'objet DirectInputDevice : Cette opération vous permet de définir le nom des constantes qui représenteront les infos de la souris (exemple: DIMOFS_BUTTON0 représente le bouton gauche). Nous n'expliquerons que le format de donné standard, mais il est possible de s'en créer un personnalisé.
4.Définir le comportement de l'unité d'entée : C'est à dire définir son niveau de coopération (pour donnée l'accès exclusif de l'unité à notre application ou bien pour permettre à d'autres applications de l'utiliser) .
5.Préparation d’un tampon.
6.Obtenir un accès à la souris.
7.Récupérer les informations de la souris (position…).
8.Libérer toutes les interfaces DirectInput

Important: N'oublier pas dans vos programmes d'inclure "dinput.h", de rajouter la ligne #define INITGUID devant l'inclusion des fichiers ( pour les identificateurs GUID), et de linker la librairie dinput8.lib.



Etape 1: Création d'un objet DirectInput

Après avoir déclarer un objet DirectInput de type LPDIRECTINPUT8 en variable globale, on appel la fonction suivante:

HRESULT WINAPI DirectInput8Create(
  		HINSTANCE hinst,	// handle d'instance de l'application
  		DWORD dwVersion,	// numéro de version de DirectInput souhaité
  		REFIID riidltf,		// identifiant de l'interface désirée
		LPVOID* ppvOut,		// pointeur vers pointeur d'objet DirectInput
		LPUNKNOWN punkOuter  	// pour des agrégats COM
		);










Le deuxième paramètre est une constante pour le numéro de la version de DirectInput que l'on désire utiliser. On lui passe simplement la constante DIRECTINPUT_VERSION pour utiliser la dernière version.

Le troisième paramètre est nouveau dans DirectX 8. C'est l'identifiant du numéro de version de l'interface DirectInput désiré. Son utilité par rapport au paramètre précédant n'est pas très claire.

Le quatrième argument est l'objet DirectInput que nous avons déclarer en variable globale.

Le dernier paramètre prend la valeur NULL dans la très grande majorité des cas.

L'interface que nous venons de créer possède plusieurs méthodes dont:
CreateDevice(): Pour Créer une unité d'entrée
EnumDevices(): Pour détecter les périphériques installés
GetDeviceStatus(): Pour détecter si le périphérique est connecter au PC
RunControlPanel(); Lance le panneau de configuration standard
Release(); Libère l'interface

Attention: Si vous utilisez plusieurs unités d'entrer gérer par DirectInput dans votre programme, vous n'avez besoin de créer qu'un seul objet DirectInput (contrairement aux objets DirectInputDevice).

Si vous devez utiliser DirectX 7, remplacez les interfaces par LPDIRECTINPUT et LPDIRECTINPUTDEVICE et utilisez la fonction suivante:
HRESULT WINAPI DirectInputCreate(
  		HINSTANCE hinst,	// handle d'instance de l'application
  		DWORD dwVersion,	// numéro de version de DirectInput souhaité  		
		LPVOID* ppvOut,		// pointeur vers pointeur d'objet DirectInput
		LPUNKNOWN punkOuter  	// pour des agrégats COM
		);












Etape 2: Créer un objet DirectInputDevice

Partant du principe que l'utilisateur à une souris (pour savoir comment détecter la présence d'une unité d'entrée allez lire le tutorial sur le joystick), on appel la méthode IDirectInput8::CreateDevice de l'interface DirectInput que l'on vient de créer.

HRESULT CreateDevice(
  		REFGUID rguid,				//identificateur GUID de l'unité à créer
  		LPDIRECTINPUTDEVICE *lplpDirectInputDevice,  	// l'objet
  		LPUNKNOWN pUnkOuter			// pour des agrégats COM = NULL
		);








Pour le clavier le premier argument est GUID_SysMouse.
Le deuxième argument est l'objet DirectInputDevice déclarer une variable globale et de type LPDIRECTINPUTDEVICE



Etape 3: Définir un format de donné pour l'objet DirectInputDevice

Pour définir le format de donné, on utilise cette méthode :
HRESULT SetDataFormat(
  		LPCDIDATAFORMAT lpdf
		);







L’argument est soit une structure de type DIDATAFORMAT (pour un format de donné personnalisé) soit la variable prédéfini : c_dfDIMouse (pour utiliser le format de donné standard).

Si vous choisissez d’utiliser un format de donné personnalisé, vous devez remplir la structure (lisez pour ça la doc du SDK).

Si vous utilisez le format de donné standard, les boutons des coordonnées de la souris auront des constantes standards pour les identifier (disponible dans la doc du SDK). Exemple : DIMOFS_BUTTON0 pour le bouton gauche.



Etape 4 : Définir le comportement de l'unité d'entée

Cette étape s'effectue grâce à la méthode IDirectInputDevice8::SetCooperativeLevel:

HRESULT SetCooperativeLevel(
  		HWND hwnd,  	//handle de la fenêtre principale
  		DWORD dwFlags  	// drapeau pour niveau coopératif
		);







Contrairement au clavier on peut donner un accès exclusif à la souris pour nos applications. C’est pourquoi les drapeaux les plus souvent utilisés et combinés sont DISCL_FOREGROUND|DISCL_EXCLUSIVE.



Etape 5 : Préparation d'un tampon.

La souris fonctionne différemment du clavier. En effet, on ne détecte pas l'état de la souris à un instant t, mais les derniers mouvements qu'elle à effectuée.Il faut donc utiliser un tampon qui gérer toutes ces informations relatives.

Mais d'abord, il faut connaître tous les mouvements de la souris à chaque instant. C'est pourquoi il faut créer ce que l'on appel un événement qui envoi des signaux à l'interface DirectInputDevice. Pour cela, on écrit ces deux lignes de code:

HANDLE hMouseEvent = CreateEvent(0,0,0,0);	// on crée l'evenement
pMouse->SetEventNotification(hMouseEvent);	// on l'associe à l'interface





Note: pMouse est notre interface DirectInputDevice.

Maintenant vous n'avez pas à créer le tampon mais à définir sa taille. Il faut pour cela remplir une structure de type DIPROPWORD de la façon suivante:

DIPROPDWORD dipdw; 
dipdw.diph.dwSize = sizeof(DIPROPDWORD); 
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
dipdw.diph.dwObj = 0; 
dipdw.diph.dwHow = DIPH_DEVICE; 
dipdw.dwData = 16; 	// taille du tampon (16 en moyenne)









On passe ensuite la taille du tampon à l'interface par la méthode IDirectInputDevice8::SetProperty de la façon suivante:

pMouse->Setproperty(DIPROP_BUFFERSIZE , &dipdw.diph);





Le premier argument est la propriété que l'on veut établir. Nous, on s'intéresse à la taille du tampon d'où la constante DIPROP_BUFFERSIZE. Le deuxième argument est l'adresse de la structure qui contient l'info.



Etape 6 : Obtenir un accès à l'unité d'entrées.

La méthode IDirectInputDevice8::Acquire suffit. Elle n’a pas d’arguments.
Cette acquisition sera perdu si votre fenêtre n'est plus active. Il vous faut donc gérer ce problème avec le message WM_ACTIVATE de votre procédure de fenêtre (cf. code source).



Etape 7 : Récupérer les informations de la souris

Les six étapes précédentes se faisaient à l’initialisation. La suite se fait dans la boucle de jeu.

Pour avoir les infos de la souris à un moment précis (coordonnées et boutons pressés) , il faut les récupérer du tampon et les stocker dans une structure de type DIDEVICEDATA (donc à déclarer). Apparemment, il faut la mette à zéro avec memset avant chaque mise à jours pour éviter les bugs. Pour cela on utilise la méthode IDirectInputDevice8::GetDeviceState. Pour la souris, cette méthode a quatre paramètres alors quelle en avait seulement deux pour le clavier.

HRESULT GetDeviceData(
	DWORD cbObjectData,		// taille de la structure 
  	LPDIDEVICEOBJECTDATA rgdodo,  // adresse de la structure 			
	LPDWORD pdwInOut,            	// nombre d'éléments à récupérer
 	DWORD dwFlags			// drapeau
);









La structure est bien sûr la structure de type DIDEVICEDATA.

Le troisième argument est l'adresse d'une variable de type DWORD que vous devez déclarer et initialiser à 1 pour ne récupérer qu'un seul élément des données de la souris. C'est à dire qu'on ne lit qu'une information sur l'état de la souris lors de l'appel de la méthode.

Le dernier argument est à mettre à 0. Sinon, DIGDD_PEEK permet de garder l'élément lu, dans le buffer.

Le troisième paramètre de la méthode si dessus a permis de stocker une seule information relative à la souris dans le champ dwData de la structure. On ne sait pas quelle est cette information (variation de sa coordonnée en x ? en y ? état d'un bouton ? ).

Pour savoir quelle est cette information, on regarde le contenu du champ dwOfs de la structure de type DIDEVICEDATA envoyé à la méthode. Si ce champ est égal à la constante DIMOFS_X, l'info stockée dans la structure est la variation de la distance parcourue par la souris en x (idem en y avec DIMOFS_Y). Pour les boutons les constantes sont DIMOFS_BUTTON0 et DIMOFS_BUTTON1.

Pour mettre à jours la position d'un objet dirigé par la souris, il suffit d'ajouté à ses coordonnées x (ou y), la valeur du champ dwData lorsque le champ dwOfs est égal à DIMOFS_X ( ou DIMOFS_Y).

Pour les boutons, c'est la même chose que pour le clavier (opérateur AND et 0x80) en remplaçant le buffer par le champ dwData de la structure.

Pour vous éclaircir les idées, regardez le code source que vous pouvez télécharger tout en haut de cette page.

Attention: ne récupérer les infos de la souris que si vous y avez accès.



Etape 8 : Libérer toutes les interfaces DirectInput

Avant la fermeture de l’application il ne faut surtout pas oublier:
1.De « déacquérir » les interfaces DirectInputDevice par la méthode IDirectInputDevice8::Unacquire (sans argument).
2.De libérer les interfaces DirectInputDevice par la méthode IDirectInputDevice8::Release (sans argument).
3.De libérer l'objet DirectInput.



Version originale: Avril 2001
Dernière mise à jour: Juin 2002
Par Grégory Smialek
www.texel.fr.fm