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

我想捕获特定用户控件中的所有按键和鼠标单击。 我需要这样做才能创建一个空闲检测,以便我可以解锁实体,如果用户在用户控件中没有做任何事情一段时间。

我的第一次尝试是PreProcessMessage来检测Windows消息,但它似乎没有被调用? 我的第二个是使用DefWndProc,但没有为那些消息调用它。

如何为用户控件及其所有子项获取WM_KEYDOWNWM_MOUSEUP

更新

ProcessKeyPreview用于检测密钥

对于键盘方面,您可以尝试覆盖UserControlProcessCmdKey事件。

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); } 

对于鼠标,我想你的UserControl实现IMessageFilter接口的PreFilterMessage方法可能是前进的方向(虽然我不确定这是否可以特定于用户控件)。

编辑

我快速浏览了一下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 windowHandles = new List(); public MessageHandler(List 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; } } 

在您的用户控件(或新类)中,您可以使用P / Invoke来获取给定父级的子窗口。 来自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 GetChildWindows(IntPtr parent, bool addParent = true) { List result = new List(); 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 list = gch.Target as List; if (list == null) { throw new InvalidCastException("GCHandle Target could not be cast as List"); } 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; } 

GetChildWindows将返回我们需要的窗口。 我修改了一下并添加了一个可选的addParent bool,它将把用户控件本身添加到列表中。

UserControl.cs构造函数中,我们可以注册MessageFilter并传递句柄列表(或者只要您知道用户控件的句柄,就可以通过其他forms添加它)。

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

您现在应该能够在用户控件及其任何子窗口中检测到三个鼠标按钮事件。 当您的应用程序关闭或UserControl关闭/处置时,不要忘记调用Application.RemoveMessageFilter

正如我所说,这不是最直接的方式,但如果标准事件处理程序不适合您,它将捕获点击(我假设您已尝试订阅标准鼠标点击事件)。

我会发现以下事件:

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以及子控件的任何单击/更改事件。 让所有事件处理程序调用相同的常用函数来保存最后一个操作的时间戳。

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

(不要忘记稍后取消订阅这些控件,如果您动态添加和删除控件,请相应地处理订阅/取消订阅。)

如果抓住它们, 无论哪个应用程序具有焦点都不是问题,您可以始终使用Gobal键盘/鼠标挂钩 。 在这里详细解释有点太复杂,但你总能在我做类似事情的地方参考我的问题 。

对于键盘,如前所述,使用:

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

这应解决鼠标事件,为您需要的每个现有鼠标事件创建新事件:

 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; } } }