简体   繁体   English

捕获用户控件中的所有鼠标点击和按键

[英]Capture ALL mouse clicks and key presses in a user control

I want to capture all key presses and mouse clicks in a specific user control .我想捕获特定用户控件中的所有按键和鼠标点击。 I need to do that to be able to create a idle detection so that I can unlock the entity if the user has not done anything in the user control for a while.我需要这样做才能创建空闲检测,以便在用户有一段时间没有在用户控件中执行任何操作时我可以解锁实体。

My first attempt was to PreProcessMessage to detect the windows messages, but it doesn't seem to be called?我的第一次尝试是使用PreProcessMessage来检测 Windows 消息,但它似乎没有被调用? My second was to use DefWndProc, but it isn't called for those messages.我的第二个是使用 DefWndProc,但它不是为那些消息调用的。

How can I get WM_KEYDOWN & WM_MOUSEUP for a user control and all of it's children?如何为用户控件及其所有子控件获取WM_KEYDOWNWM_MOUSEUP

Update更新

ProcessKeyPreview works to detect keys ProcessKeyPreview用于检测密钥

For the keyboard aspect you could try overriding the ProcessCmdKey event within the UserControl .对于键盘方面,您可以尝试覆盖UserControlProcessCmdKey事件。

UserControl.cs : UserControl.cs

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //a key has been pressed within your user control
    //invoke event or some other action
    //...

    return base.ProcessCmdKey(ref msg, keyData);
}

For the mouse, I imagine your UserControl implementing the IMessageFilter interface's PreFilterMessage method may be the direction to head in (although I'm not sure if that can be specific to a user control).对于鼠标,我想您的 UserControl 实现IMessageFilter接口的PreFilterMessage方法可能是前进的方向(尽管我不确定这是否特定于用户控件)。

Edit编辑

I had a quick look at IMessageFilter and I think I have something that may work although it does seem a bit convoluted.我快速浏览了IMessageFilter ,我认为我有一些可能IMessageFilter东西,尽管它看起来有点令人费解。

Create a MessageHandler that implements IMessageFilter .创建一个实现IMessageFilterMessageHandler

class MessageHandler : IMessageFilter
{
     private int WM_LBUTTONUP = 0x0202; //left mouse up
     private int WM_MBUTTONUP = 0x0208; //middle mouse up
     private int WM_RBUTTONUP = 0x0205; //right mouse up

     //stores the handles of the children controls (and actual user control)
     List<IntPtr> windowHandles = new List<IntPtr>();
     public MessageHandler(List<IntPtr> wnds)
     {
         windowHandles = wnds;
     }


     public bool PreFilterMessage(ref Message m)
     {
         //make sure that any click is within the user control's window or 
         //its child controls before considering it a click (required because IMessageFilter works application-wide)
         if (windowHandles.Contains(m.HWnd) && (m.Msg == WM_LBUTTONUP || m.Msg == WM_MBUTTONUP || m.Msg == WM_RBUTTONUP))
         {
              Debug.WriteLine("Clicked");                
         }
         return false;
     }
 }

In your user control (or new class) you can use P/Invoke to get the child windows of a given parent.在您的用户控件(或新类)中,您可以使用 P/Invoke 来获取给定父级的子窗口。 From pinvoke.net来自pinvoke.net

public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

private static List<IntPtr> GetChildWindows(IntPtr parent, bool addParent = true)
{
    List<IntPtr> result = new List<IntPtr>();
    GCHandle listHandle = GCHandle.Alloc(result);
    try
    {
        EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
        EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
    }
    finally
    {
        if (listHandle.IsAllocated)
           listHandle.Free();
    }


    if (addParent)
      result.Add(parent);

    return result;
}


private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
    GCHandle gch = GCHandle.FromIntPtr(pointer);
    List<IntPtr> list = gch.Target as List<IntPtr>;
    if (list == null)
    {
        throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
    }
    list.Add(handle);
    //  You can modify this to check to see if you want to cancel the operation, then return a null here
    return true;
}

The GetChildWindows will return the windows we need. GetChildWindows将返回我们需要的窗口。 I modified it a bit and added an optional addParent bool which will add the user control itself to the list.我稍微修改了它并添加了一个可选的addParent bool,它将用户控件本身添加到列表中。

In your UserControl.cs constructor we can register the MessageFilter and pass the list of handles (or you can add this via a different form as long as you know the handle of the user control).在您的UserControl.cs构造函数中,我们可以注册MessageFilter并传递句柄列表(或者您可以通过不同的形式添加它,只要您知道用户控件的句柄)。

public MyControl()
{
    InitializeComponent();
    Application.AddMessageFilter(new MessageHandler(GetChildWindows(this.Handle)));
}

You should now be able to detect the three mouse button up events in your user control and any of its child windows.您现在应该能够检测到用户控件及其任何子窗口中的三个鼠标按钮向上事件。 Don't forget to call Application.RemoveMessageFilter when your application is closed or when your UserControl is closed/disposed.不要忘记在您的应用程序关闭或UserControl关闭/处置时调用Application.RemoveMessageFilter

As I say, this isn't the most straightforward way, but it'll capture the clicks if the standard event handlers aren't working for you (I assume you've tried subscribing to the standard mouseclick events).正如我所说,这不是最直接的方法,但如果标准事件处理程序不适合您,它会捕获点击(我假设您已经尝试订阅标准鼠标点击事件)。

I would catch the following events:我会捕捉以下事件:

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.click.aspx http://msdn.microsoft.com/en-us/library/system.windows.forms.control.textchanged.aspx And any click/changed events for subcontrols. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.click.aspx http://msdn.microsoft.com/en-us/library/system.windows.forms.control .textchanged.aspx以及子控件的任何单击/更改事件。 Have all the event handlers call the same common function that saves a timestamp of the last action.让所有事件处理程序调用相同的公共函数来保存最后一个操作的时间戳。

Click += ClickHandler;
TextChanged += ChangedHandler;

foreach(var control in Controls)
{
    control.Click += ClickHandler;
    control.TextChanged += ChangedHandler;
}

(Don't forget to unsubscribe to these controls later, and if you have controls dynamically getting added and removed, handle the subscribe/unsubscribe appropriately.) (不要忘记稍后取消订阅这些控件,如果您有控件动态添加和删除,请适当处理订阅/取消订阅。)

If catching them no matter which application has the focus isn't a problem, you could always use a Gobal Keyboard/Mouse hook .如果无论哪个应用程序具有焦点都可以捕获它们不是问题,那么您始终可以使用Gobal Keyboard/Mouse hook It is a bit too complicated to explain in detail here but you can always refer to my question where I did something similar.在这里详细解释有点太复杂了,但你可以随时参考我的问题,我做了类似的事情。

For keyboard, as already mentioned, use:对于键盘,如前所述,请使用:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //invoke event or some other action
    return base.ProcessCmdKey(ref msg, keyData);
}

This should solve for mouse events, create new ones for each existing mouse event you need:这应该解决鼠标事件,为您需要的每个现有鼠标事件创建新事件:

public new event MouseEventHandler MouseClick
{
    add
    {
        base.MouseClick += value;
        foreach (Control control in Controls)
        {
            control.MouseClick += value;
        }
    }
    remove
    {
        base.MouseClick -= value;
        foreach (Control control in Controls)
        {
            control.MouseClick -= value;
        }
    }
}

public new event MouseEventHandler MouseDoubleClick
{
    add
    {
        base.MouseDoubleClick += value;
        foreach (Control control in Controls)
        {
            control.MouseDoubleClick += value;
        }
    }
    remove
    {
        base.MouseDoubleClick -= value;
        foreach (Control control in Controls)
        {
            control.MouseDoubleClick -= value;
        }
    }
}

public new event EventHandler DoubleClick
{
    add
    {
        base.DoubleClick += value;
        foreach (Control control in Controls)
        {
            control.DoubleClick += value;
        }
    }
    remove
    {
        base.DoubleClick -= value;
        foreach (Control control in Controls)
        {
            control.DoubleClick -= value;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM