2010-01-14 6 views
10

Je souhaite capturer l'événement de déplacement de la souris dans mon formulaire principal. Bien que je puisse câbler le MouseEventHandler pour le formulaire principal, l'événement ne se déclenche plus lorsque le curseur se trouve sur un UserControl ou tout autre contrôle. Comment puis-je m'assurer que j'ai toujours la position de la souris.Comment capturer l'événement de déplacement de la souris

+0

Utilisez IMessageFilter comme expliqué dans le thread dup. –

Répondre

18

Vous pouvez utiliser un crochet de souris de bas niveau. Voir l'exemple this et recherchez le message WM_MOUSEMOVE dans HookCallback.

Vous pouvez également utiliser la classe IMessageFilter pour attraper les événements de souris et de déclencher un événement pour obtenir la position (note: ce n'obtenir la position sur la fenêtre, pas à l'extérieur de celui-ci):

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace GlobalMouseEvents 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
     GlobalMouseHandler gmh = new GlobalMouseHandler(); 
     gmh.TheMouseMoved += new MouseMovedEvent(gmh_TheMouseMoved); 
     Application.AddMessageFilter(gmh); 

     InitializeComponent(); 
     } 

     void gmh_TheMouseMoved() 
     { 
     Point cur_pos = System.Windows.Forms.Cursor.Position; 
     System.Console.WriteLine(cur_pos); 
     } 
    } 

    public delegate void MouseMovedEvent(); 

    public class GlobalMouseHandler : IMessageFilter 
    { 
     private const int WM_MOUSEMOVE = 0x0200; 

     public event MouseMovedEvent TheMouseMoved; 

     #region IMessageFilter Members 

     public bool PreFilterMessage(ref Message m) 
     { 
     if (m.Msg == WM_MOUSEMOVE) 
     { 
      if (TheMouseMoved != null) 
      { 
       TheMouseMoved(); 
      } 
     } 
     // Always allow message to continue to the next filter control 
     return false; 
     } 

     #endregion 
    } 
} 
+1

Cela fonctionne très bien, merci. J'ai utilisé la source que vous avez publiée ici. J'ai remarqué, cependant, que la fonction MouseMoved est appelée en continu, même si la souris ne bouge pas. Il arrête de tirer quand la souris n'est pas au-dessus de l'application. –

+0

@ SwDevMan81 Comment les gens peuvent-ils trouver des codes hexadécimaux pour identifier les messages? Je vois tous ces appels d'importation avec des appels dll User32 et je me demande vraiment où trouver des informations à ce sujet – Dbl

+1

@ AndreasMüller - [Notifications de clavier] (http://msdn.microsoft.com/en-us/library/windows/desktop/ ff468861 (v = vs.85) .aspx) et [Notifications de la souris] (http://msdn.microsoft.com/fr-fr/library/windows/desktop/ff468877 (v = vs.85) .aspx) – SwDevMan81

6

Voici la solution. Bien que je puisse voir une autre réponse avec une approche similaire. Mais depuis que je l'ai écrit, je veux l'afficher. Ici MouseMessageFilter a un appel d'événement statique MouseMove auquel vous pouvez vous abonner n'importe où dans l'application.

static class Program 
{ 
    [STAThread] 
    static void Main() { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false);    
     Application.AddMessageFilter(new MouseMessageFilter()); 
     MouseMessageFilter.MouseMove += new MouseEventHandler(OnGlobalMouseMove); 

     Application.Run(new MainForm()); 
    } 

    static void OnGlobalMouseMove(object sender, MouseEventArgs e) { 
     Console.WriteLine(e.Location.ToString()); 
    } 
} 

class MouseMessageFilter : IMessageFilter 
{ 
    public static event MouseEventHandler MouseMove = delegate { }; 
    const int WM_MOUSEMOVE = 0x0200; 

    public bool PreFilterMessage(ref Message m) { 

     if (m.Msg == WM_MOUSEMOVE) { 

      Point mousePosition = Control.MousePosition; 

      MouseMove(null, new MouseEventArgs(
       MouseButtons.None, 0, mousePosition.X, mousePosition.Y,0)); 
     }  
     return false; 
    } 
} 
+0

cela ne fonctionne que si wm_mousemove est envoyé à votre application (qui est l'un des états actifs de la fenêtre ou sous le curseur de la souris) si seulement un formulaire est intéressé, alors vous devez vérifier si ce formulaire est actif. .btw il se déclenche quand d'autres fenêtres sont actives aussi. et vous n'avez pas à ajouter votre filtre avant l'exécution de l'application. – TakeMeAsAGuest

1
public partial class frmCaptureMouse : Form 
{ 
    [DllImport("user32.dll")] 
    static extern IntPtr SetCapture(IntPtr hWnd); 

    public frmCaptureMouse() 
    { 
     InitializeComponent(); 
    } 

    private void frmCaptureMouse_MouseMove(object sender, MouseEventArgs e) 
    { 
     try 
     { 
      lblCoords.Text = e.Location.X.ToString() + ", " + e.Location.Y.ToString(); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 

    private void btnCapture_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      SetCapture(this.Handle); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 
} 
0

J'ai essayé le solutoution mentionné ci-dessus fournies par @ SwDevMan81. Bien que cela fonctionne bien, j'ai aussi eu le problème @Randy Gamage mentionné "que la fonction MouseMoved est appelée en permanence, même si la souris ne bouge pas.Il arrête de tirer quand la souris n'est pas sur l'application". En tout cas, ce que je suis venu avec:

Dans le constructeur du formulaire:

GlobalMouseHandler.MouseMovedEvent += GlobalMouseHandler_MouseMovedEvent; 
Application.AddMessageFilter(new GlobalMouseHandler()); 

InitializeComponent(); 

Le gestionnaire d'événements:

private void GlobalMouseHandler_MouseMovedEvent(object sender, MouseEventArgs e) 
{ 
    try 
    { 
     //Do whatever ... 
    } 
    catch { } 
} 

Et ma classe GlobalMouseHandler légèrement modifiée:

public class GlobalMouseHandler : IMessageFilter 
{ 
    private const int WM_MOUSEMOVE = 0x0200; 
    private System.Drawing.Point previousMousePosition = new System.Drawing.Point(); 
    public static event EventHandler<MouseEventArgs> MouseMovedEvent = delegate { }; 

    #region IMessageFilter Members 

    public bool PreFilterMessage(ref System.Windows.Forms.Message m) 
    { 
     if (m.Msg == WM_MOUSEMOVE) 
     { 
      System.Drawing.Point currentMousePoint = Control.MousePosition; 
      if (previousMousePosition != currentMousePoint) 
      { 
       previousMousePosition = currentMousePoint; 
       MouseMovedEvent(this, new MouseEventArgs(MouseButtons.None, 0, currentMousePoint.X, currentMousePoint.Y, 0)); 
      } 
     } 
     // Always allow message to continue to the next filter control 
     return false; 
    } 

    #endregion 
} 

J'espère que quelqu'un peut l'utiliser.

+0

Cela a une bonne réponse, mais il appelle la méthode deux fois –

+0

Je comprends pourquoi il appelle la méthode deux fois parce que lorsque l'événement a tiré pour la première fois 'previousMousePosition' a une valeur de' x = 0; y = 0' et quand le programme saute à 'if (previousMousePosition!= currentMousePoint) 'il retourne true, j'ajoute juste une condition qui va vérifier si' previousMousePosition' a une valeur par défaut et quitter la fonction avant l'instruction 'if'. Cela résout le problème –

Questions connexes