2010-01-14 114 views
10

我想捕獲我的主窗體中的鼠標移動事件。儘管我可以爲主窗體連接MouseEventHandler,但當光標位於UserControl或其他任何控件上時,事件不再觸發。我如何確保我始終擁有鼠標位置。如何捕獲鼠標移動事件

+0

按照dup線程中的說明使用IMessageFilter。 – 2010-01-14 12:46:30

回答

18

您可以使用低級別的鼠標鉤子。請參閱this示例,並檢查HookCallback中的WM_MOUSEMOVE消息。

您也可以使用IMessageFilter類抓老鼠事件和觸發事件,以獲得位置(注意:這隻會位置在窗口,它不是外面):

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

這很好,謝謝。我使用了您在此處發佈的來源。不過,我注意到,即使鼠標沒有移動,MouseMoved函數也會不斷調用。當鼠標不在應用程序上時,它停止發射。 – 2013-05-28 21:10:25

+0

@ SwDevMan81人們如何找出查找消息ID的十六進制代碼的位置?我看到所有這些導入調用與User32 dll調用,我真的想知道在哪裏可以找到有關此信息 – Dbl 2014-08-01 13:35:41

+1

@AndreasMüller - [鍵盤通知](http://msdn.microsoft.com/en-us/library/windows/desktop/ ff468861(v = vs.85).aspx)和[鼠標通知](http://msdn.microsoft.com/en-us/library/windows/desktop/ff468877(v = vs.85).aspx) – SwDevMan81 2014-08-01 14:27:44

6

這是解決方案。儘管我可以用類似的方法看到另一個答案。但是自從我寫了它以後,我想發佈它。這裏MouseMessageFilter有一個靜態事件調用MouseMove,你可以從應用程序中的任何地方訂閱。

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

只有當wm_mousemove發送給你的應用程序(當它的一個窗口的活動狀態或它的鼠標光標下),如果只有單一表單感興趣,那麼你需要檢查該表單是否有效。 .btw它會在其他窗口處於活動狀態時觸發。並且在運行應用程序之前,您不必添加過濾器。 – TakeMeAsAGuest 2015-07-09 19:32:21

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

我試圖通過@ SwDevMan81提供上述solutoution。雖然它的效果很好,但我也遇到了@Randy Gamage的問題,「即使鼠標沒有移動,MouseMoved函數也會被連續調用,當鼠標不在應用程序時它會停止觸發。 在這無論如何是我想出了:

在窗體的構造函數:

​​

的事件處理程序:

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

而且我稍微改變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 
} 

我希望有人可以使用它。

+0

這有一個很好的答案,但它調用方法兩次 – 2016-08-16 08:53:44

+0

我弄清楚爲什麼它調用該方法兩次,因爲當第一次觸發事件'previousMousePosition'有一個值'x = 0; y = 0',當程序跳轉到'if(previousMousePosition!= currentMousePoint)'它返回true,我只是添加一個條件來檢查'previousMousePosition'是否有一個默認值並在'if'語句之前退出函數。這解決了這個問題 – 2016-08-19 01:57:38