I. Introduction ♪▲
Aujourd'hui, de plus en plus de monde a son joystick posé sur le coin du bureau. Grce aux efforts des designers, on peut dire que si on n’en a pas trop l'usage (tout le monde n'est pas passionné par Flight Simulator et ses congénères), ça fait presque « œuvre d'art ». Et dans un monde où les PC sont taillés à la hache, c'est déjà pas mal ! Cependant, pour faire plaisir aux gestionnaires, on aimerait bien leur trouver une utilité supplémentaire (surtout pour que Mademoiselle notre copine arrête de nous dire « mais t'as encore acheté un truc inutile ?!? Ça va te servir à quoi ? T'en avais pas assez comme ça pour encombrer le bureau ?!"). Hé bien que diriez-vous si on en faisait une télécommande ? Certes elle est à fil, mais c'est tout de même mieux que de se lever pour aller monter le volume du film quand c'est pas assez fort et inversement.
Je me propose donc d'étudier avec vous les possibilités que nous offre Windows pour la gestion des joysticks à travers la réalisation d'une télécommande.
II. Fonctionnement▲
Afin de mieux utiliser les fonctions associées au joystick, voyons tout d'abord comment il fonctionne. Tout d'abord, le joystick est un périphérique passif, c'est-à-dire que contrairement au clavier, il ne va pas déclencher d'évènements dans le système (interruption ou autre). C'est donc le système d'exploitation qui est chargé, via le pilote associé, d'aller interroger le joystick sur son état. Bien sûr, pour éviter de surcharger le système, cette interrogation est faite en temps réel, à la demande des programmes clients. Afin de différencier chacun des périphériques connectés à la machine, Windows leur attribue un numéro identifiant. Cet identifiant est celui affiché dans le panneau de contrôle des périphériques de jeu auquel il faut retrancher 1 (pourquoi faire simple quand on peut faire compliqué ?). Le système peut supporter jusqu'à 16 périphériques et fourni pour répondre aux besoins les plus courants deux constantes : JOYSTICKID1 et JOYSTICKID2 qui correspondent aux deux premiers périphériques (héritage de Windows 3.x et précédents).
Avant toute chose, on va devoir commencer par apprendre le joystick qu'on veut manipuler. En effet, comment gérer un joystick si on ne connaît pas ses caractéristiques ? Nombre de boutons ? Les types d'axes ? Y a-t-il un point de vue ? Nous allons donc commencer par nous renseigner sur les capacités du joystick, puis voir le fonctionnement de la capture avant de nous enfoncer dans les méandres de l'interrogation du joystick.
III. Obtenir les caractéristiques du joystick▲
III-A. Liste des périphériques connectés▲
Avant de rechercher les caractéristiques d'un joystick, il faut nous assurer qu'il est connecté. Pour cela nous allons utiliser la fonction joyGetPos() qui renvoie deux constantes : JOYERR_NOERROR si le joystick est connecté, ou JOYERR_UNPLUGGED si le joystick n'est pas connecté. Cependant, ce n'est pas parce que le joystick d'ID 0 n'est pas connecté qu'aucun ne l'est : il faut tester tous les ID. Voyons un exemple de code qui affiche les ID des joysticks connectés :
#include <windows.h>
#include <stdio.h>
...
void
AfficherJoysConnectes
(
)
{
int
i;
JOYINFO structtmp;
printf
(
"
Voici la liste des joysticks connectés :
\n
"
);
for
(
i =
JOYSTICKID1 ; i <
(
JOYSTICKID1 +
16
) ; i++
) //seuls 16 IDs sont possibles
{
if
(
joyGetPos
(
i,&
structtmp) ==
JOYERR_NOERROR)
printf
(
"
%d
\n
"
,i);
}
}
III-B. Caractéristiques d'un périphérique▲
Maintenant qu'on sait comment détecter la présence d'un joystick, nous allons pouvoir nous pencher sur le problème de la récupération des caractéristiques. L'API Microsoft fournit à cet effet la fonction joyGetDevCaps() qui prend trois paramètres et renvoie JOYERR_NOERROR si tout se passe bien. Les trois paramètres sont l'ID du joystick à interroger, l'adresse vers une structure de type JOYCAPS où seront stockées les informations et la taille de cette structure afin que Windows puisse détecter la version utilisée par le programme. Voyons le contenu de la structure de caractéristiques :
WORD wMid |
ID du manufacteur |
WORD wPid |
ID du produit |
CHAR szPname[MAXPNAMELEN] |
nom du produit |
UINT wXmin |
valeur minimale de l'axe X |
UINT wXmax |
valeur maximale de l'axe X |
UINT wYmin |
valeur minimale de l'axe Y |
UINT wYmax |
valeur maximale de l'axe Y |
UINT wZmin |
valeur minimale de l'axe Z (Gaz) |
UINT wZmax |
valeur maximale de l'axe Z (Gaz) |
UINT wNumButtons |
nombre de boutons du périphérique |
UINT wPeriodMin |
Période minimale à utiliser lors de la capture |
UINT wPeriodMax |
Période maximale à utiliser lors de la capture |
UINT wRmin |
valeur minimale de l'axe R (palloniers) |
UINT wRmax |
valeur maximale de l'axe R (palonniers) |
UINT wUmin |
valeur minimale de l'axe U |
UINT wUmax |
valeur maximale de l'axe U |
UINT wVmin |
valeur minimale de l'axe V |
UINT wVmax |
y'a pas idée d'avoir autant d'axes ! ;-) |
UINT wCaps |
Zone de drapeaux indiquant les capacités du périphérique |
UINT wMaxAxes |
Nombre d'axes que le joystick peut gérer |
UINT wNumAxes |
Nombre d'axes actuellement utilisés |
UINT wMaxButtons |
Nombre de boutons que le joystick peut gérer |
CHAR szRegKey[MAXPNAMELEN] |
Clé du registre associée au joystick |
CHAR szOEMVxD[MAX_JOYSTICKOEMVXDNAME] |
Nom du driver du joystick |
wCaps utilise les drapeaux suivants :
- JOYCAPS_HASZ : l'axe Z existe.
- JOYCAPS_HASR : l'axe R existe.
- JOYCAPS_HASU : l'axe U existe.
- JOYCAPS_HASV : l'axe V existe.
- JOYCAPS_HASPOV : le joystick peut fournir des informations de point de vue.
- JOYCAPS_POV4DIR : le joystick ne reconnaît que les valeurs d'orientation discrète (haute, basse, gauche et droite).
- JOYCAPS_POVCTS : le joystick reconnaît les valeurs d'orientation continues en degrés.
Voyons un exemple de programme qui affiche les capacités d'un périphérique :
#include <windows.h>
#include <stdio.h>
...
void
AfficherCaracs
(
UINT JoyID)
{
JOYCAPS InfosCaps;
if
(
joyGetDevCaps
(
JoyID, &
InfosCaps, sizeof
(
JOYCAPS)) ==
JOYERR_NOERROR)
{
printf
(
"
\n
Nom du périphérique : %s
"
, InfoCaps.szPname);
printf
(
"
Nombre d'axes possibles : %d, gérables : %d
\n
"
,
InfoCaps.wNumAxes, InfoCaps.wMaxAxes);
printf
(
"
Axe | Min | Max
\n
"
);
printf
(
"
----+-------+-------
\n
"
);
printf
(
"
X | ] | ]
\n
"
, InfoCaps.wXMin, InfoCaps.wXMax);
printf
(
"
Y | ] | ]
\n
"
, InfoCaps.wYMin, InfoCaps.wYMax);
if
(
InfoCaps.wCaps &
JOYCAPS_HASZ)
printf
(
"
Z | ] | ]
\n
"
, InfoCaps.wZMin, InfoCaps.wZMax);
else
printf
(
"
Z | Absent
\n
"
);
if
(
InfoCaps.wCaps &
JOYCAPS_HASR)
printf
(
"
R | ] | ]
\n
"
, InfoCaps.wRMin, InfoCaps.wRMax);
else
printf
(
"
R | Absent
\n
"
);
if
(
InfoCaps.wCaps &
JOYCAPS_HASU)
printf
(
"
U | ] | ]
\n
"
, InfoCaps.wUMin, InfoCaps.wUMax);
else
printf
(
"
U | Absent
\n
"
);
if
(
InfoCaps.wCaps &
JOYCAPS_HASV)
printf
(
"
V | ] | ]
\n
"
, InfoCaps.wVMin, InfoCaps.wVMax);
else
printf
(
"
V | Absent
\n
"
);
printf
(
"
\n
Point de vue :
"
);
if
(
InfoCaps.wCaps &
JOYCAPS_HASPOV)
{
if
(
InfoCaps.wCaps &
JOYCAPS_POV4DIR)
printf
(
"
Quadridirectionnel
\n
"
);
else
printf
(
"
Continu
\n
"
);
}
else
printf
(
"
Absent
\n
"
);
printf
(
"
Nombre de boutons possibles : %d, gérables : %d
\n
"
,
InfoCaps.wNumButtons, InfoCaps.wMaxButtons);
}
}
IV. La capture du Joystick▲
Afin d'éviter aux programmeurs d'avoir à réaliser un thread séparé s'occupant de la gestion du joystick afin de ne pas perturber l'application principale, Microsoft a mis à la disposition des programmeurs une fonctionnalité spécifique : la capture du joystick. La capture du joystick permet de se décharger de la gestion du joystick et de recevoir des messages associés au joystick. Comme tout, cela a également des désavantages : seule une application à la fois peut capturer un joystick, un maximum de deux joysticks peuvent être capturés au même moment, et les messages sont assez limités et ne permettent pas de contrôler complètement les joysticks actuels. Par ailleurs, il se peut qu'un message n'arrive pas jusqu'à l'application qui a capturé le joystick si une autre fait appel à joyGetPos() à peu près au même moment que le message est envoyé.
IV-A. La capture▲
Il y a deux types de captures possibles : la première envoie des messages à intervalles réguliers (entre wPeriodMin et wPeriodMax) et la seconde envoie des messages quand il y a un changement d'état. La capture est mise en place par la fonction joySetCapture() qui prend quatre paramètres et renvoie JOYERR_NOERROR si tout se passe bien. Les quatre paramètres sont : le handle de la fenêtre à laquelle Windows doit envoyer les messages, l'ID du joystick à capturer, la période de temps entre deux tests d'état et le type de capture (FALSE pour la première et TRUE pour la seconde). Dans le cas du second type de capture, l'application devrait également préciser l'amplitude minimale de mouvement sur un axe pour laquelle on considère qu'il y a changement d'état en faisant un appel à la fonction joySetThreshold(). Cette dernière prend deux paramètres : l'ID du joystick et la quantité de mouvement. Pour connaître la valeur actuelle, on peut utiliser la fonction joyGetThreshold() qui prend en paramètres l'ID du joystick et l'adresse d'un entier non signé de type UINT. Les deux fonctions renvoient JOYERR_NOERROR quand tout se passe bien. Bien entendu, lorsque l'application n'a plus besoin du joystick, elle peut relcher la capture en faisant un appel à la fonction joyReleaseCapture() qui prend en paramètre l'ID du joystick à relcher et renvoie toujours la même constante si tout se passe bien. Voyons un exemple de capture du joystick basée sur le changement d'état (cet exemple utilise l'API pour créer une fenêtre, voyez ici pour un tutoriel de Bob sur l'utilisation de l'API).
#ifndef Unit1H
#define Unit1H
LRESULT CALLBACK WndProc
(
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
fichier principal (
WinMain) : capture.c
//---------------------------------------------------------------------------
#include <windows.h>
#include "Unit1.h"
//---------------------------------------------------------------------------
HINSTANCE hInst; // instance de l'application
LPCTSTR lpszAppName =
"
CAPTURE
"
;
LPCTSTR lpszTitle =
"
Capture du joystick
"
;
HWND ZoneTexte;
WINAPI WinMain
(
HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASSEX wc;
MMRESULT ret;
// Enregistrement des caractéristiques du class name de la fenêtre
wc.style =
CS_HREDRAW |
CS_VREDRAW |
CS_DBLCLKS;
wc.lpfnWndProc =
(
WNDPROC)WndProc;
wc.cbClsExtra =
0
;
wc.cbWndExtra =
0
;
wc.hInstance =
0
;
wc.hIcon =
LoadIcon
(
hInstance, lpszAppName);
wc.hCursor =
LoadCursor
(
NULL
, IDC_ARROW);
wc.hbrBackground =
(
HBRUSH)(
COLOR_WINDOW);
wc.lpszMenuName =
lpszAppName;
wc.lpszClassName =
lpszAppName;
wc.cbSize =
sizeof
(
WNDCLASSEX);
wc.hIconSm =
NULL
;
if
(!
RegisterClassEx
(&
wc))
return
FALSE;
hInst =
hInstance;
// Création de la fenêtre
hWnd =
CreateWindow
(
lpszAppName, lpszTitle, WS_OVERLAPPEDWINDOW,
0
, 0
, 300
, 300
, NULL
, NULL
, hInstance, NULL
);
if
(!
hWnd)
return
FALSE;
// Affichage de la fenêtre
ShowWindow
(
hWnd,nCmdShow);
// Création d'une zone de texte dans la fenêtre
ZoneTexte =
CreateWindow
(
"
EDIT
"
, ""
, WS_VISIBLE |
WS_VSCROLL |
WS_CHILD
|
ES_AUTOVSCROLL |
ES_MULTILINE , 1
, 2
, 290
, 270
,
hWnd, NULL
, hInstance, NULL
);
UpdateWindow
(
hWnd);
// Capture du joystick
ret =
joySetCapture
(
hWnd, // les messages seront envoyés à la fenêtre
JOYSTICKID1, // capture du premier joystick
50
, // période de 50 ms. Si c'est hors bornes, Windows ajuste
TRUE); // Basée sur les changements d'état
if
(
ret ==
JOYERR_NOERROR)
{
// ajuster les valeurs en fonction des caractéristiques du joystick
// ici, c'est environ 3% pour le mien
joySetThreshold
(
JOYSTICKID1, 2000
);
}
else
PostQuitMessage
(
0
);
// lancement de la boucle de traitement des messages
while
(
GetMessage
(&
msg, NULL
, 0
, 0
))
{
TranslateMessage
(&
msg);
DispatchMessage
(&
msg);
}
return
(
msg.wParam);
}
IV-B. Les messages associés à la capture▲
Voyons maintenant quels sont les messages que Windows envoie à l'application qui a capturé un joystick. Tout d'abord, afin de différencier les joysticks Windows préfixe le nom des constantes de messages par MM_JOY1 ou MM_JOY2. Il y a quatre types de messages :
MM_JOY1BUTTONDOWN |
Un bouton a été pressé |
MM_JOY1BUTTONUP |
Un bouton a été relâché |
MM_JOY1MOVE |
La position de l'axe X ou Y a changé |
MM_JOY1ZMOVE |
La position de l'axe Z a changé |
Pour les deux premiers messages, wParam contient des drapeaux pour indiquer les changements d'état et les boutons enfoncés à l'aide des constantes JOY_BUTTONxCHG et JOY_BUTTONx (x compris entre 1 et 4). Pour les deux autres, wParam ne contient que les boutons enfoncés et seules les constantes JOY_BUTTONx sont utilisées.
Pour les trois premiers messages, LOWORD(lParam) contient la coordonnée X et HIWORD(lParam) la coordonnée Y par rapport au coin supérieur gauche de la fenêtre. Le dernier message ne complète que LOWORD(lParam) avec la coordonnée Z.
Voyons un exemple de code qui va modifier le contenu de la zone de texte créée précédemment en fonction du message reçu (suite du fichier principal : capture.c):
LRESULT CALLBACK WndProc
(
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
UINT wID;
HWND hwndCtrl;
char
Texte[1000
];
char
b1,b2,b3,b4;
switch
(
uMsg)
{
case
MM_JOY1BUTTONDOWN :
b1 =
(
wParam &
JOY_BUTTON1) ? '
O
'
: '
N
'
;
b2 =
(
wParam &
JOY_BUTTON2) ? '
O
'
: '
N
'
;
b3 =
(
wParam &
JOY_BUTTON3) ? '
O
'
: '
N
'
;
b4 =
(
wParam &
JOY_BUTTON4) ? '
O
'
: '
N
'
;
sprintf
(
Texte,"
Boutons enfoncés :
\r\n
1 : %c
\r\n
2 : %c
\r\n
3 : %c
\r\n
4 : %c
"
,
b1, b2, b3, b4);
break
;
case
MM_JOY1BUTTONUP :
b1 =
(
wParam &
JOY_BUTTON1) ? '
O
'
: '
N
'
;
b2 =
(
wParam &
JOY_BUTTON2) ? '
O
'
: '
N
'
;
b3 =
(
wParam &
JOY_BUTTON3) ? '
O
'
: '
N
'
;
b4 =
(
wParam &
JOY_BUTTON4) ? '
O
'
: '
N
'
;
sprintf
(
Texte,"
Boutons enfoncés :
\r\n
1 : %c
\r\n
2 : %c
\r\n
3 : %c
\r\n
4 : %c
"
,
b1, b2, b3, b4);
break
;
case
MM_JOY1MOVE :
sprintf
(
Texte,"
Axe X : %d
\r\n
Axe Y %d
"
,LOWORD
(
lParam), HIWORD
(
lParam));
break
;
case
MM_JOY1ZMOVE :
sprintf
(
Texte,"
Axe Z : %d
"
,LOWORD
(
lParam);
break
;
case
WM_DESTROY :
PostQuitMessage
(
0
);
break
;
default
:
return
(
DefWindowProc
(
hWnd, uMsg, wParam, lParam));
}
SetWindowText
(
ZoneTexte,Texte);
return
0L
;
}
V. L'interrogation du Joystick▲
Voyons maintenant comment faire lorsque la capture ne permet pas de résoudre nos problèmes ou qu'il est préférable de contrôler le déroulement des opérations par nous même. En effet, la capture ne permet que de gérer quatre boutons et trois axes ce qui est limité si on veut transformer notre merveilleux petit outil en télécommande.
Windows fournit une fonction avancée pour interroger le joystick de manière plus complète que ce que permet la capture. Pour l'interrogation, il y a les fonctions joyGetPos() et joyGetPosEx() ; nous ne nous occuperons pas de la première puisqu'elle n'apporte rien par rapport à la capture, nous ne verrons donc que la seconde. Cette fonction prend en paramètres l'ID du joystick à interroger ainsi que l'adresse d'une structure JOYINFOEX et renvoie JOYERR_NOERROR quand tout se passe bien. Voyons en détail le contenu de la structure JOYINFOEX :
DWORD dwSize |
Taille de la structure (nécessaire pour détecter la version utilisée) |
DWORD dwFlags |
Drapeaux indiquant les données qu'on souhaite obtenir |
DWORD dwXpos |
Positions des différents axes du joystick |
DWORD dwYpos |
|
DWORD dwZpos |
|
DWORD dwRpos |
|
DWORD dwUpos |
|
DWORD dwVpos |
|
DWORD dwButtons |
Etat des boutons (jusqu'à 32 boutons) |
DWORD dwButtonNumber |
Nombre de boutons pressés |
DWORD dwPOV |
Position du point de vue |
DWORD dwReserved1 |
Réservé (pourquoi faire, je ne sais pas €¦ ), ne pas utiliser |
DWORD dwReserved2 |
À la lumière de ces informations, on peut déjà se réjouir en imaginant ce qu'on va pouvoir faire faire à notre manette de jeu. Que dis-je notre baguette magique spéciale PC ;-). Voyons maintenant un peu plus en détail les quelques spécificités de cette structure. Tout d'abord dwButtons : pour connaître l'état d'un bouton, il suffit de lire l'état du bit correspondant : au bouton 1 correspond le bit de poids le plus faible et ainsi de suite jusqu'au 32e bouton auquel correspond le bit de poids le plus fort. Ensuite, dwPOV : cette variable contient l'orientation du point de vue en centièmes de degrés (90° <=> 9000). Windows fournit cinq constantes correspondant aux positions primaires : JOY_POVCENTERED (-1 : centre), JOY_POVBACKWARD (18000 : arrière), JOY_POVFORWARD (0 : avant), JOY_POVLEFT (27000 : gauche) et JOYPOVRIGHT (9000 : droite). Finalement, il ne nous reste plus qu'à indiquer à Windows quelles sont les informations dont on a besoin, et c'est le rôle de dwFlags. Voici un tableau récapitulatif des drapeaux utilisables.
JOY_RETURNALL |
Équivalent à mettre tous les bits JOY_RETURN à l'exception de JOY_RETURNRAWDATA. |
JOY_RETURNBUTTONS |
dwButtons contient des informations valides à propos de chaque bouton. |
JOY_RETURNCENTERED |
Centre la position neutre du joystick au milieu de chaque axe. |
JOY_RETURNPOV |
dwPOV contient des informations valides à propos du point de vue exprimé à l'aide des constantes énoncées ci-dessus (utile pour les applications qui ne gèrent que les positions discrètes quand le joystick fournit des informations continues). |
JOY_RETURNPOVCTS |
dwPOV contient des informations valides a propos du point de vue exprimées en valeurs discrètes. |
JOY_RETURNR |
dwRpos, dwUpos, dwVpos, dwXpos, dwYpos et/ou dwZpos contiennent des informations valides sur les positions des axes |
JOY_RETURNU |
|
JOY_RETURNV |
|
JOY_RETURNX |
|
JOY_RETURNY |
|
JOY_RETURNZ |
|
JOY_USEDEADZONE |
Etend la zone morte du joystick. Le driver renvoie une valeur constante tant qu'il est dans la zone morte. |
JOY_RETURNRAWDATA |
Les données contenues dans la structure sont des données brutes (non calibrées) |
Les drapeaux suivants fournissent des informations pour calibrer le joystick. Je ne les ai jamais utilisées, alors n'hésitez pas à me faire part de vos expériences afin de compléter ce tutoriel.
JOY_CAL_READ3 |
Lit les données brutes X, Y et Z et les fournit par l'intermédiaire de dwXpos et ses consœurs. |
JOY_CAL_READ4 |
Lit les données brutes X, Y, Z et R et les fournit par l'intermédiaire de dwXpos et ses consœurs. |
JOY_CAL_READ5 |
Lit les données brutes X, Y, Z, R et U et les fournit par l'intermédiaire de dwXpos et ses consœurs. |
JOY_CAL_READ6 |
Lit les données brutes X, Y, Z, R, U et V et les fournit par l'intermédiaire de dwXpos et ses consœurs. |
JOY_CAL_READALWAYS |
Lit les données du joystick même si le driver indique qu'il n'est pas présent. |
JOY_CAL_READRONLY |
Lit uniquement les données brutes associées à(aux) l'axe(s) indiqués. |
JOY_CAL_READXONLY |
|
JOY_CAL_READXYONLY |
|
JOY_CAL_READYONLY |
|
JOY_CAL_READZONLY |
|
JOY_CAL_READUONLY |
|
JOY_CAL_READVONLY |
Nous allons maintenant mettre ces informations en œuvre pour utiliser le joystick à la place de la souris. Pour plus d'informations, je vous oriente vers mon tutoriel sur le contrôle du clavier et de la souris. Dans cet exemple, je ne ferais aucune vérification quant aux caractéristiques du joystick : je considère que le joystick à contrôler est connu et qu'il n'y aura aucun problème. Si votre périphérique ne prend pas en charge l'une de ces caractéristiques, vous n'aurez qu'à la mettre en commentaire.
#include <windows.h>
#define BOUTON1 1
#define BOUTON2 2
#define BOUTON3 4
#define BOUTON4 8
int
CalculerDeplacement
(
UINT Max, UINT Min, UINT Val);
WINAPI WinMain
(
HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow)
{
JOYINFOEX ActualPos; // État actuel et dernier état du joystick
DWORD dwBoutons; // Masque pour récupérer l'état des boutons
UINT uMax[2
], uMin[2
]; // Maximums et minimums de chacun des axes
UINT uPoolPeriod; // Temps entre deux interrogations du joystick
JOYCAPS InfosCaps; // Infos sur les capacités du joystick
BOOL bStop; // Test d'arrêt de la boucle (bouton 4)
POINT Curseur; // Curseur de la souris
// initialisation du temps d'attente avec un minimum de 20 millisecondes
uPoolPeriod =
20
;
if
(
joyGetDevCaps
(
JOYSTICKID1, &
InfosCaps, sizeof
(
JOYCAPS)) !=
JOYERR_NOERROR)
return
0
;
// Initialisation de la structure informationnelle avec sa taille
ActualPos.dwSize =
sizeof
(
JOYINFOEX);
// Initialisation des autres membres que la taille de la structure à 0
// (Plus rapide que d'affecter 0 à chaque élément. En effet, il est
// obligatoire que tous les membres soient nuls sous peine d'échec)
memset
(&(
ActualPos.dwFlags),0
,sizeof
(
JOYINFOEX) -
sizeof
(
DWORD));
// Initialisation des variables d'état actuel avant de lancer la boucle
// de gestion du joystick
ActualPos.dwFlags =
JOY_RETURNALL;
joyGetPosEx
(
JOYSTICKID1,&
ActualPos);
dwBoutons =
ActualPos.dwButtons;
bStop =
FALSE;
// Lancement de la gestion du joystick
while
(!
bStop)
{
// on réinitialise ActualPos avant d'appeler l'API
// pour savoir la position actuelle du joystick
memset
(&(
ActualPos.dwFlags),0
,sizeof
(
JOYINFOEX) -
sizeof
(
DWORD));
ActualPos.dwFlags =
JOY_RETURNALL;
joyGetPosEx
(
JOYSTICKID1,&
ActualPos);
// Position du curseur
GetCursorPos
(&
Curseur);
// Gestion de l'axe X
Curseur.x +=
CalculerDeplacement
(
InfosCaps.wXmin, InfosCaps.wXmax, ActualPos.dwXpos);
// Gestion de l'axe Y
Curseur.y +=
CalculerDeplacement
(
InfosCaps.wYmin, InfosCaps.wYmax, ActualPos.dwYpos);
// Déplacement du curseur
SetCursorPos
(
Curseur.x, Curseur.y);
// Gestion de la molette avec le point de vue
if
(
ActualPos.dwPOV ==
JOY_POVFORWARD)
mouse_event
(
MOUSEEVENTF_WHEEL,Curseur.x,Curseur.y, 120
, 0
);
else
if
(
ActualPos.dwPOV ==
JOY_POVBACKWARD)
mouse_event
(
MOUSEEVENTF_WHEEL,Curseur.x,Curseur.y, -
120
, 0
);
// Test de l'état des boutons
// on teste l'état du bouton et on agit uniquement
// si il y a eu un changement d'état
if
((
ActualPos.dwButtons &
BOUTON1) &&
!(
dwBoutons &
BOUTON1))
mouse_event
(
MOUSEEVENTF_LEFTDOWN,Curseur.x,Curseur.y, 0
, 0
);
else
if
(!(
ActualPos.dwButtons &
BOUTON1) &&
(
dwBoutons &
BOUTON1))
mouse_event
(
MOUSEEVENTF_LEFTUP,Curseur.x,Curseur.y, 0
, 0
);
if
((
ActualPos.dwButtons &
BOUTON2) &&
!(
dwBoutons &
BOUTON2))
mouse_event
(
MOUSEEVENTF_MIDDLEDOWN,Curseur.x,Curseur.y, 0
, 0
);
else
if
(!(
ActualPos.dwButtons &
BOUTON2) &&
(
dwBoutons &
BOUTON2))
mouse_event
(
MOUSEEVENTF_MIDDLEUP,Curseur.x,Curseur.y, 0
, 0
);
if
((
ActualPos.dwButtons &
BOUTON3) &&
!(
dwBoutons &
BOUTON3))
mouse_event
(
MOUSEEVENTF_RIGHTDOWN,Curseur.x,Curseur.y, 0
, 0
);
else
if
(!(
ActualPos.dwButtons &
BOUTON3) &&
(
dwBoutons &
BOUTON3))
mouse_event
(
MOUSEEVENTF_RIGHTUP,Curseur.x,Curseur.y, 0
, 0
);
if
(
ActualPos.dwButtons &
BOUTON4)
bStop =
TRUE;
dwBoutons =
ActualPos.dwButtons;
// On patiente avant de retester la position du joystick
Sleep
(
uPoolPeriod);
}
return
0
;
}
//---------------------------------------------------------------------------
int
CalculerDeplacement
(
UINT Max, UINT Min, UINT Val)
{
// On calcule la position actuelle en pourcentage et on en déduit le mouvement
float
PCent =
(
float
)(
Val) /
(
float
)(
Min -
Max) *
100
.0
;
PCent -=
50
.0
;
PCent /=
10
.0
;
if
((
PCent <
1
) &&
(
PCent >
-
1
))
PCent =
0
.0
;
return
(
int
)(
PCent);
}