Как мне захватить событие перемещения мыши - PullRequest
12 голосов
/ 14 января 2010

Я хотел бы зафиксировать событие перемещения мыши в моей основной форме. Хотя я могу подключить MouseEventHandler для основной формы, событие больше не срабатывает, когда курсор находится над UserControl или любым другим элементом управления. Как мне убедиться, что у меня всегда есть положение мыши.

Ответы [ 5 ]

22 голосов
/ 14 января 2010

Вы можете использовать низкоуровневый крючок для мыши. См. этот пример и проверьте наличие сообщения WM_MOUSEMOVE в HookCallback.

Вы также можете использовать класс 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
   }
}
7 голосов
/ 14 января 2010

Вот решение. Хотя я вижу другой ответ с подобным подходом. Но так как я написал это, я хочу опубликовать это. Здесь 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 голосов
/ 04 апреля 2019

Вот решение для WPF с глобальным обработчиком мыши для всего приложения. Я использую это также из-за других проблем с мышью в WPF.

с использованием System.Windows.Interop;

private const int WM_MOUSEMOVE = 0x0200;
public delegate void Del_MouseMovedEvent(Point mousePosition);

// Relative to this control, the mouse position will calculated
public IInputElement Elmt_MouseMovedRelativeElement = null;

// !! This is static; needs special treatment in a multithreaded application !!
public static event Del_MouseMovedEvent Evt_TheMouseMoved = null;

// your main function call
public MyMainWindows()
{
    // install the windows message filter first
    ComponentDispatcher.ThreadFilterMessage += ComponentDispatcher_ThreadFilterMessage;

    InitializeComponent();

    ...
}   

// filtering the windows messages
private void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)
{
    if(msg.message == WM_MOUSEMOVE)
    {
        this.Evt_TheMouseMoved?.Invoke(Mouse.GetPosition(this.Elmt_MouseMovedRelativeElement));
    }
}

// individual event for mouse movement
private void MyMouseMove(Point mousePoint)
{
    // called on every mouse move when event is assigned
    Console.WriteLine(mousePoint.X + " " + mousePoint.Y);
}

private void AnyFunctionDeeperInTheCode()
{
    // assign the handler to the static var of the main window
    MyMainWindows.Evt_TheMouseMoved += MyMouseMove;

    // set the element / control to which the mouse position should be calculated; 
    MyMainWindows.Elmt_MouseMovedRelativeElement = this;

    ...

    // undassign the handler from the static var of the main window
    MyMainWindows.Evt_TheMouseMoved -= MyMouseMove;
}
0 голосов
/ 21 апреля 2015

Я попробовал вышеупомянутое решение, предоставленное @ SwDevMan81. Хотя это работало хорошо, у меня также была проблема @Randy Gamage, в которой говорилось, что «функция MouseMoved вызывается непрерывно, даже если мышь не движется. Она прекращает работу, когда мышь не находится над приложением». В любом случае это то, что я придумал:

В конструкторе формы:

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

InitializeComponent();

Обработчик события:

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 голосов
/ 13 января 2013
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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...