Partager via


Déplacement de la souris

Lorsque la souris se déplace, Windows publie un message WM_MOUSEMOVE. Par défaut, WM_MOUSEMOVE accède à la fenêtre qui contient le curseur. Vous pouvez remplacer ce comportement par capture la souris, qui est décrite dans la section suivante.

Le message WM_MOUSEMOVE contient les mêmes paramètres que les messages pour les clics de souris. Les 16 bits les plus bas de lParam contiennent la coordonnée x, et les 16 bits suivants contiennent la coordonnée y. Utilisez les macros GET_X_LPARAM et GET_Y_LPARAM pour décompresser les coordonnées de lParam. Le paramètre wParam contient une ou d’indicateurs au niveau du bit, indiquant l’état des autres boutons de la souris ainsi que les touches Maj et Ctrl. Le code suivant obtient les coordonnées de la souris de lParam.

int xPos = GET_X_LPARAM(lParam); 
int yPos = GET_Y_LPARAM(lParam);

N’oubliez pas que ces coordonnées sont en pixels, et non en pixels indépendants de l’appareil (DIPs). Plus loin dans cette rubrique, nous allons examiner le code qui se convertit entre les deux unités.

Une fenêtre peut également recevoir un message WM_MOUSEMOVE si la position du curseur change par rapport à la fenêtre. Par exemple, si le curseur est positionné sur une fenêtre et que l’utilisateur masque la fenêtre, la fenêtre reçoit WM_MOUSEMOVE messages même si la souris n’a pas été déplacée. L’une des conséquences de ce comportement est que les coordonnées de la souris peuvent ne pas changer entre les messages WM_MOUSEMOVE.

Capture du mouvement de la souris en dehors de la fenêtre

Par défaut, une fenêtre cesse de recevoir des messages WM_MOUSEMOVE si la souris se déplace au-delà du bord de la zone cliente. Toutefois, pour certaines opérations, vous devrez peut-être suivre la position de la souris au-delà de ce point. Par exemple, un programme de dessin peut permettre à l’utilisateur de faire glisser le rectangle de sélection au-delà du bord de la fenêtre, comme illustré dans le diagramme suivant.

une illustration de la capture de souris.

Pour recevoir des messages de déplacement de souris au-delà du bord de la fenêtre, appelez la fonction SetCapture. Une fois cette fonction appelée, la fenêtre continue de recevoir des messages WM_MOUSEMOVE tant que l’utilisateur conserve au moins un bouton de souris vers le bas, même si la souris se déplace en dehors de la fenêtre. La fenêtre de capture doit être la fenêtre de premier plan, et une seule fenêtre peut être la fenêtre de capture à la fois. Pour libérer la capture de la souris, appelez la fonction ReleaseCapture.

Vous utilisez généralement SetCapture et ReleaseCapture de la manière suivante.

  1. Lorsque l’utilisateur appuie sur le bouton gauche de la souris, appelez SetCapture pour commencer à capturer la souris.
  2. Répondez aux messages de déplacement de la souris.
  3. Lorsque l’utilisateur relâche le bouton gauche de la souris, appelez ReleaseCapture.

Exemple : dessin de cercles

Étendons le programme Circle de module 3 en permettant à l’utilisateur de dessiner un cercle avec la souris. Commencez par l’exemple de cercle direct2D 'exemple de. Nous allons modifier le code dans cet exemple pour ajouter un dessin simple. Tout d’abord, ajoutez une nouvelle variable membre à la classe MainWindow.

D2D1_POINT_2F ptMouse;

Cette variable stocke la position vers le bas de la souris pendant que l’utilisateur fait glisser la souris. Dans le constructeur MainWindow, initialisez les variables ellipse et ptMouse.

    MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL),
        ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)),
        ptMouse(D2D1::Point2F())
    {
    }

Supprimez le corps de la méthode MainWindow::CalculateLayout ; il n’est pas nécessaire pour cet exemple.

void CalculateLayout() { }

Ensuite, déclarez les gestionnaires de messages pour le bouton gauche vers le bas, le bouton gauche vers le haut et les messages de déplacement de la souris.

void OnLButtonDown(int pixelX, int pixelY, DWORD flags);
void OnLButtonUp();
void OnMouseMove(int pixelX, int pixelY, DWORD flags);

Les coordonnées de la souris sont données en pixels physiques, mais Direct2D attend des pixels indépendants de l’appareil (DIPs). Pour gérer correctement les paramètres haute résolution, vous devez traduire les coordonnées de pixels en ADRESSES IP. Pour plus d’informations sur l’ppp, consultez ppp et Device-Independent pixels. Le code suivant montre une classe d’assistance qui convertit des pixels en DIPs.

class DPIScale
{
    static float scale;

public:
    static void Initialize(HWND hwnd)
    {
        float dpi = GetDpiForWindow(hwnd);
        scale = dpi/96.0f;
    }

    template <typename T>
    static D2D1_POINT_2F PixelsToDips(T x, T y)
    {
        return D2D1::Point2F(static_cast<float>(x) / scale, static_cast<float>(y) / scale);
    }
};

float DPIScale::scale = 1.0f;

Appelez DPIScale ::Initialize dans votre gestionnaire de WM_CREATE, après avoir créé l’objet de fabrique Direct2D.

case WM_CREATE:
    if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
    {
        return -1;  // Fail CreateWindowEx.
    }
    DPIScale::Initialize(hwnd);
    return 0;

Pour obtenir les coordonnées de la souris dans les ADRESSES IP à partir des messages de la souris, procédez comme suit :

  1. Utilisez les macros GET_X_LPARAM et GET_Y_LPARAM pour obtenir les coordonnées de pixels. Ces macros sont définies dans WindowsX.h. N’oubliez donc pas d’inclure cet en-tête dans votre projet.
  2. Appelez DPIScale::PixelsToDips pour convertir des pixels en ADRESSES IP.

Ajoutez maintenant les gestionnaires de messages à votre procédure de fenêtre.

case WM_LBUTTONDOWN: 
    OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
    return 0;

case WM_LBUTTONUP: 
    OnLButtonUp();
    return 0;

case WM_MOUSEMOVE: 
    OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
    return 0;

Enfin, implémentez les gestionnaires de messages eux-mêmes.

Bouton gauche vers le bas

Pour le message vers le bas du bouton gauche, procédez comme suit :

  1. Appelez SetCapture pour commencer à capturer la souris.
  2. Stockez la position du clic de souris dans la variable ptMouse. Cette position définit le coin supérieur gauche de la zone englobante pour l’ellipse.
  3. Réinitialisez la structure de points de suspension.
  4. Appelez invalidateRect. Cette fonction force la fenêtre à repeindre.
void MainWindow::OnLButtonDown(int pixelX, int pixelY, DWORD flags)
{
    SetCapture(m_hwnd);
    ellipse.point = ptMouse = DPIScale::PixelsToDips(pixelX, pixelY);
    ellipse.radiusX = ellipse.radiusY = 1.0f; 
    InvalidateRect(m_hwnd, NULL, FALSE);
}

Déplacement de la souris

Pour le message de déplacement de la souris, vérifiez si le bouton gauche de la souris est enfoncé. Si c’est le cas, recalculez les points de suspension et repeindrez la fenêtre. Dans Direct2D, un ellipse est défini par le point central et les rayons x et y. Nous voulons dessiner un ellipse qui correspond au cadre englobant défini par le point vers le bas de la souris (ptMouse) et la position actuelle du curseur (x, y), donc un peu d’arithmétique est nécessaire pour trouver la largeur, la hauteur et la position de l’ellipse.

Le code suivant recalcule l’ellipse, puis appelle InvalidateRect pour repeindre la fenêtre.

Diagramme montrant un ellipse avec des rayons x et y.

void MainWindow::OnMouseMove(int pixelX, int pixelY, DWORD flags)
{
    if (flags & MK_LBUTTON) 
    { 
        const D2D1_POINT_2F dips = DPIScale::PixelsToDips(pixelX, pixelY);

        const float width = (dips.x - ptMouse.x) / 2;
        const float height = (dips.y - ptMouse.y) / 2;
        const float x1 = ptMouse.x + width;
        const float y1 = ptMouse.y + height;

        ellipse = D2D1::Ellipse(D2D1::Point2F(x1, y1), width, height);

        InvalidateRect(m_hwnd, NULL, FALSE);
    }
}

Bouton gauche vers le haut

Pour le message de bouton gauche, appelez simplement ReleaseCapture pour libérer la capture de la souris.

void MainWindow::OnLButtonUp()
{
    ReleaseCapture(); 
}

Prochain