2010-01-14 17 views
10

Me gustaría capturar el evento de mover el mouse en mi formulario principal. Aunque puedo conectar el MouseEventHandler para el formulario principal, el evento ya no se dispara cuando el cursor está sobre un UserControl o cualquier otro control. ¿Cómo me aseguro de que siempre tenga la posición del mouse?Cómo capturo el evento de mover el mouse

+0

Use IMessageFilter como se explica en el subproceso dúplex. –

Respuesta

18

Puede usar un gancho de mouse de bajo nivel. Vea el ejemplo this y busque el mensaje WM_MOUSEMOVE en HookCallback.

También se puede utilizar la clase IMessageFilter para atrapar a los eventos de ratón y desencadenar un evento para obtener la posición (nota: esto sólo se conseguirá la posición sobre la ventana, no fuera de él):

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

Esto funciona genial, gracias. Usé la fuente que publicaste aquí. Sin embargo, me di cuenta de que la función MouseMoved se llama continuamente, incluso aunque el mouse no se mueva. Deja de disparar cuando el mouse no está sobre la aplicación. –

+0

@ SwDevMan81 ¿Cómo averigua la gente dónde buscar los códigos hexadecimales para identificar los mensajes? Veo todas esas llamadas Import con llamadas a User32 dll y realmente me pregunto dónde encontrar información sobre este – Dbl

+1

@ AndreasMüller - [Notificaciones de teclado] (http://msdn.microsoft.com/en-us/library/windows/desktop/ ff468861 (v = vs.85) .aspx) y [Notificaciones de mouse] (http://msdn.microsoft.com/en-us/library/windows/desktop/ff468877 (v = vs.85) .aspx) – SwDevMan81

6

Aquí está la solución. Aunque puedo ver otra respuesta con un enfoque similar. Pero desde que lo escribí quiero publicarlo. Aquí MouseMessageFilter tiene un evento estático llamada MouseMove que puede suscribirse desde cualquier lugar dentro de la aplicación.

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

esto solo funciona si wm_mousemove se envía a su aplicación (que es cuando uno de sus ventana está activa o está debajo del cursor del mouse) si solo está interesado en una sola forma, entonces necesita verificar si esa forma está activa. .btw se dispara cuando otras ventanas están activas también. y no tienes que agregar tu filtro antes de ejecutar la aplicación. – 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

Probé la solutoution mencionada proporcionada por @ SwDevMan81. Aunque funcionó bien, también tuve el problema @Randy Gamage mencionó "que la función MouseMoved se llama continuamente, aunque el mouse no se mueva. Deja de disparar cuando el mouse no está sobre la aplicación". En cualquier caso, esto es lo que ocurrió:

En la forma constructor:

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

InitializeComponent(); 

El controlador de eventos:

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

Y mi ligeramente alterada clase GlobalMouseHandler:

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 
} 

Espero que alguien pueda usarlo.

+0

Esto tiene una buena respuesta pero llama al método dos veces –

+0

Me explico por qué llama al método dos veces porque cuando el evento se disparó por primera vez 'previousMousePosition' tiene un valor de' x = 0; y = 0' y cuando el programa saltar a 'if (previousMousePosition!= currentMousePoint) 'devuelve verdadero, solo agrego una condición que verificará si' previousMousePosition' tiene un valor predeterminado y saldrá de la función antes de la instrucción 'if'. Esto resuelve el problema –

Cuestiones relacionadas