Opérations diverses de la souris
Les sections précédentes ont abordé les clics de souris et le mouvement de la souris. Voici d’autres opérations qui peuvent être effectuées avec la souris.
Faire glisser des éléments d’interface utilisateur
Si votre interface utilisateur prend en charge le glissement d’éléments d’interface utilisateur, il existe une autre fonction que vous devez appeler dans votre gestionnaire de messages avec la souris : DragDetect. La fonction DragDetect retourne TRUE si l’utilisateur initie un mouvement de souris qui doit être interprété comme un glisser-déplacer. Le code suivant montre comment utiliser cette fonction.
case WM_LBUTTONDOWN:
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (DragDetect(m_hwnd, pt))
{
// Start dragging.
}
}
return 0;
Voici l’idée : Lorsqu’un programme prend en charge le glisser-déplacer, vous ne souhaitez pas que chaque clic de souris soit interprété comme un glisser-déplacer. Sinon, l’utilisateur peut faire glisser accidentellement quelque chose alors qu’il voulait simplement cliquer dessus (par exemple, pour le sélectionner). Mais si une souris est particulièrement sensible, il peut être difficile de garder la souris parfaitement immobile tout en cliquant. Par conséquent, Windows définit un seuil de glissement de quelques pixels. Lorsque l’utilisateur appuie sur le bouton de la souris, il n’est pas considéré comme un glissement, sauf si la souris dépasse ce seuil. La fonction DragDetect teste si ce seuil est atteint. Si la fonction retourne TRUE, vous pouvez interpréter le clic de la souris comme un glissement. Sinon, ne le faites pas.
Notes
Si DragDetect renvoie FALSE, Windows supprime le message WM_LBUTTONUP lorsque l’utilisateur relâche le bouton de la souris. Par conséquent, n’appelez pas DragDetect , sauf si votre programme est actuellement dans un mode qui prend en charge le glissement. (Par exemple, si un élément d’interface utilisateur pouvant être fait glisser est déjà sélectionné.) À la fin de ce module, nous verrons un exemple de code plus long qui utilise la fonction DragDetect .
Confisage du curseur
Vous pouvez parfois restreindre le curseur à la zone cliente ou à une partie de la zone cliente. La fonction ClipCursor limite le mouvement du curseur à un rectangle spécifié. Ce rectangle étant donné dans les coordonnées de l’écran, plutôt que dans les coordonnées client, le point (0, 0) signifie le coin supérieur gauche de l’écran. Pour traduire les coordonnées du client en coordonnées d’écran, appelez la fonction ClientToScreen.
Le code suivant limite le curseur à la zone cliente de la fenêtre.
// Get the window client area.
RECT rc;
GetClientRect(m_hwnd, &rc);
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
ClientToScreen(m_hwnd, &pt);
ClientToScreen(m_hwnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
// Confine the cursor.
ClipCursor(&rc);
ClipCursor prend une structure RECT , mais ClientToScreen prend une structure POINT . Un rectangle est défini par ses points en haut à gauche et en bas à droite. Vous pouvez limiter le curseur à n’importe quelle zone rectangulaire, y compris les zones situées à l’extérieur de la fenêtre, mais le fait de le limiter à la zone cliente est un moyen classique d’utiliser la fonction. Le fait de limiter le curseur à une région entièrement située à l’extérieur de votre fenêtre serait inhabituel, et les utilisateurs y verraient probablement un bogue.
Pour supprimer la restriction, appelez ClipCursor avec la valeur NULL.
ClipCursor(NULL);
Événements de suivi de la souris : pointez et quittez
Deux autres messages de souris sont désactivés par défaut, mais peuvent être utiles pour certaines applications :
- WM_MOUSEHOVER : le curseur a survolé la zone cliente pendant une période fixe.
- WM_MOUSELEAVE : le curseur a quitté la zone cliente.
Pour activer ces messages, appelez la fonction TrackMouseEvent .
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
La structure TRACKMOUSEEVENT contient les paramètres de la fonction . Le membre dwFlags de la structure contient des indicateurs de bits qui spécifient les messages de suivi qui vous intéressent. Vous pouvez choisir d’obtenir à la fois WM_MOUSEHOVER et WM_MOUSELEAVE, comme indiqué ici, ou simplement l’un des deux. Le membre dwHoverTime spécifie la durée pendant laquelle la souris doit pointer avant que le système génère un message de pointage. Cette valeur est donnée en millisecondes. La constante HOVER_DEFAULT signifie utiliser la valeur par défaut du système.
Une fois que vous avez obtenu l’un des messages que vous avez demandés, la fonction TrackMouseEvent se réinitialise. Vous devez l’appeler à nouveau pour obtenir un autre message de suivi. Toutefois, vous devez attendre le prochain message de déplacement de la souris avant d’appeler à nouveau TrackMouseEvent . Sinon, votre fenêtre risque d’être inondée de messages de suivi. Par exemple, si la souris pointe, le système continue à générer un flux de messages WM_MOUSEHOVER alors que la souris est stationnaire. Vous ne voulez pas réellement un autre message WM_MOUSEHOVER jusqu’à ce que la souris passe à un autre endroit et pointe à nouveau.
Voici une petite classe d’assistance que vous pouvez utiliser pour gérer les événements de suivi de souris.
class MouseTrackEvents
{
bool m_bMouseTracking;
public:
MouseTrackEvents() : m_bMouseTracking(false)
{
}
void OnMouseMove(HWND hwnd)
{
if (!m_bMouseTracking)
{
// Enable mouse tracking.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}
void Reset(HWND hwnd)
{
m_bMouseTracking = false;
}
};
L’exemple suivant montre comment utiliser cette classe dans votre procédure de fenêtre.
LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOUSEMOVE:
mouseTrack.OnMouseMove(m_hwnd); // Start tracking.
// TODO: Handle the mouse-move message.
return 0;
case WM_MOUSELEAVE:
// TODO: Handle the mouse-leave message.
mouseTrack.Reset(m_hwnd);
return 0;
case WM_MOUSEHOVER:
// TODO: Handle the mouse-hover message.
mouseTrack.Reset(m_hwnd);
return 0;
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
Les événements de suivi de la souris nécessitent un traitement supplémentaire par le système. Laissez-les donc désactivés si vous n’en avez pas besoin.
Pour l’exhaustivité, voici une fonction qui interroge le système pour le délai d’expiration du pointage par défaut.
UINT GetMouseHoverTime()
{
UINT msec;
if (SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &msec, 0))
{
return msec;
}
else
{
return 0;
}
}
Roulette de la souris
La fonction suivante vérifie si une roulette de souris est présente.
BOOL IsMouseWheelPresent()
{
return (GetSystemMetrics(SM_MOUSEWHEELPRESENT) != 0);
}
Si l’utilisateur fait pivoter la roulette de la souris, la fenêtre avec le focus reçoit un message WM_MOUSEWHEEL . Le paramètre wParam de ce message contient une valeur entière appelée delta qui mesure la distance de rotation de la roulette. Le delta utilise des unités arbitraires, où 120 unités sont définies comme la rotation nécessaire pour effectuer une « action ». Bien sûr, la définition d’une action dépend de votre programme. Par exemple, si la roulette de la souris est utilisée pour faire défiler le texte, chaque unité de rotation de 120 ferait défiler une ligne de texte.
Le signe du delta indique le sens de rotation :
- Positif : faites pivoter vers l’avant, loin de l’utilisateur.
- Négatif : faites pivoter vers l’arrière, vers l’utilisateur.
La valeur du delta est placée dans wParam avec des indicateurs supplémentaires. Utilisez la macro GET_WHEEL_DELTA_WPARAM pour obtenir la valeur du delta.
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
Si la roulette de la souris a une résolution élevée, la valeur absolue du delta peut être inférieure à 120. Dans ce cas, s’il est logique que l’action se produise par incréments plus petits, vous pouvez le faire. Par exemple, le texte peut défiler par incréments de moins d’une ligne. Sinon, accumulez le delta total jusqu’à ce que la roue pivote suffisamment pour effectuer l’action. Stockez le delta inutilisé dans une variable et, lorsque 120 unités s’accumulent (positives ou négatives), exécutez l’action.
Suivant