Revit API Hook 之 拦截鼠标双击元素事件
2017-10-03 18:04
190 查看
阅读本文章前应具有一定编程基础和 Window API 相关知识
第一步,先封装HookBase抽象类,因所有Hook的都具有注册、卸载逻辑,且注册、卸载大同小易。如下:
第二步 ,因鼠标Hook分为线程鼠标Hook以及全局鼠标Hook两种,仅注册方式有点区别。为使用方便,将其封装为事件注册方式。如下
第三步,依次实现线程鼠标Hook以及全局鼠标Hook.
第四步,有了鼠标Hook,我们如果在Revit内使用并且拦截鼠标双击元素事件呢?我们继续封装一个元素监控类 ,如下:
第五步,调用测试,如下
第一步,先封装HookBase抽象类,因所有Hook的都具有注册、卸载逻辑,且注册、卸载大同小易。如下:
public abstract class HookBase : IHook { private static Dictionary<int, IHook> m_Hooks; private IntPtr m_ProcessId; private int m_ThreadId; private HookType m_HookType; private HookProc m_HookProc; protected internal int m_HookId; static HookBase() { m_Hooks = new Dictionary<int, IHook>(); } private HookBase(HookType hookType) { m_HookType = hookType; m_HookProc = HookProc; } protected HookBase(IntPtr processId, HookType hookType) : this(hookType) { m_ProcessId = processId; if (m_ProcessId == IntPtr.Zero) { m_ProcessId = HookHelper.GetCurrentProcessId(); } } protected HookBase(int threadId, HookType hookType) : this(hookType) { m_ThreadId = threadId; if (m_ThreadId == 0) { m_ThreadId = HookHelper.GetCurrentThreadId(); } } public void Install() { if (m_ThreadId != 0) { m_HookId = HookHelper.SetWindowsHookEx(m_HookType, m_HookProc, IntPtr.Zero, m_ThreadId); } else { if (m_ProcessId == IntPtr.Zero) { return; } m_HookId = HookHelper.SetWindowsHookEx(m_HookType, m_HookProc, m_ProcessId, 0); } if (m_HookId == 0) { return; } if (!m_Hooks.ContainsKey(m_HookId)) { m_Hooks.Add(m_HookId, this); } } public void Uninstall() { if (m_HookId == 0) { return; } var flag = HookHelper.UnhookWindowsHookEx(m_HookId); if (flag) { if (m_Hooks.Remove(m_HookId)) { m_HookId = 0; } } } protected abstract int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
第二步 ,因鼠标Hook分为线程鼠标Hook以及全局鼠标Hook两种,仅注册方式有点区别。为使用方便,将其封装为事件注册方式。如下
public abstract class MouseHookBase : HookBase { protected MouseHookBase(IntPtr processId) f8e6 : base(processId, HookType.WH_MOUSE_LL) { } protected MouseHookBase(int threadId) : base(threadId, HookType.WH_MOUSE) { } /// <summary> /// 鼠标双击 /// </summary> public event HookHandler<MouseEventArgs> MouseDoubleClick; /// <summary> /// 鼠标移动 /// </summary> public event HookHandler<MouseEventArgs> MouseMove; /// <summary> /// 鼠标按下 /// </summary> public event HookHandler<MouseEventArgs> MouseDown; /// <summary> /// 鼠标弹起 /// </summary> public event HookHandler<MouseEventArgs> MouseUp; protected override int HookProc(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode < 0) { return HookHelper.CallNextHookEx(m_HookId, nCode, wParam, lParam); } var mouseMsg = (MouseMessage)wParam.ToInt32(); var mouseHookStruct = lParam.ToStruct<MOUSEHOOKSTRUCT>(); var button = this.GetMouseButtons(mouseMsg); switch (mouseMsg) { case MouseMessage.WM_LBUTTONDOWN: case MouseMessage.WM_RBUTTONDOWN: case MouseMessage.WM_MBUTTONDOWN: return this.OnRaiseMouseDown(button, 1, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData); case MouseMessage.WM_LBUTTONUP: case MouseMessage.WM_MBUTTONUP: case MouseMessage.WM_RBUTTONUP: return this.OnRaiseMouseUp(button, 1, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData); case MouseMessage.WM_LBUTTONDBLCLK: case MouseMessage.WM_RBUTTONDBLCLK: case MouseMessage.WM_MBUTTONDBLCLK: return this.OnRaiseMouseDoubleClick(button, 2, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData); case MouseMessage.WM_MOUSEMOVE: return this.OnRaiseMouseMove(MouseButtons.None, 0, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData); default: return HookHelper.CallNextHookEx(m_HookId, nCode, wParam, lParam); } } private MouseButtons GetMouseButtons(MouseMessage mouseMsg) { MouseButtons result = MouseButtons.None; switch (mouseMsg) { case MouseMessage.WM_LBUTTONDBLCLK: case MouseMessage.WM_LBUTTONDOWN: case MouseMessage.WM_LBUTTONUP: result = MouseButtons.Left; break; case MouseMessage.WM_MBUTTONDBLCLK: case MouseMessage.WM_MBUTTONDOWN: case MouseMessage.WM_MBUTTONUP: result = MouseButtons.Middle; break; case MouseMessage.WM_RBUTTONDBLCLK: case MouseMessage.WM_RBUTTONDOWN: case MouseMessage.WM_RBUTTONUP: result = MouseButtons.Right; break; } return result; } private int OnRaiseMouseDoubleClick(MouseButtons button, int clicks, int x, int y, int delta) { if (this.MouseDoubleClick != null) { return this.MouseDoubleClick(this, new MouseEventArgs(button, clicks, x, y, delta)); } return 0; } private int OnRaiseMouseDown(MouseButtons button, int clicks, int x, int y, int delta) { if (this.MouseDown != null) { return this.MouseDown(this, new MouseEventArgs(button, clicks, x, y, delta)); } return 0; } private int OnRaiseMouseUp(MouseButtons button, int clicks, int x, int y, int delta) { if (this.MouseUp != null) { return this.MouseUp(this, new MouseEventArgs(button, clicks, x, y, delta)); } return 0; } private int OnRaiseMouseMove(MouseButtons button, int clicks, int x, int y, int delta) { if (this.MouseMove != null) { return this.MouseMove(this, new MouseEventArgs(button, clicks, x, y, delta)); } return 0; } }
第三步,依次实现线程鼠标Hook以及全局鼠标Hook.
/// <summary> /// 线程鼠标Hook. /// </summary> /// <seealso cref="DotNet.Hook.Achieve.MouseHookBase" /> public class MouseHook : MouseHookBase { public MouseHook(int threadId = 0) : base(threadId) { } } /// <summary> /// 全局鼠标钩子 /// </summary> /// <seealso cref="DotNet.Hook.Achieve.MouseHookBase" /> public class GlobalMouseHook : MouseHookBase { public GlobalMouseHook(IntPtr processId) : base(processId) { } }
第四步,有了鼠标Hook,我们如果在Revit内使用并且拦截鼠标双击元素事件呢?我们继续封装一个元素监控类 ,如下:
/// <summary> /// 元素监控. /// </summary> public class ElementMonitor { private static ElementMonitor m_Instance; private MouseHook m_MouseHook; private bool m_IsMonitor; private UIApplication m_UIApplication; private ElementMonitor(UIApplication uiApp) { m_Instance = this; m_UIApplication = uiApp; m_MouseHook = new MouseHook(); m_MouseHook.Install(); m_MouseHook.MouseDoubleClick += OnRaiseMouseDoubleClick; } /// <summary> /// 静态实例,可在入口类判断此实例是否为null,防止重复注册. /// </summary> public static ElementMonitor Instance { get { return m_Instance; } } /// <summary> /// 当鼠标双击元素时触发此事件. /// </summary> public event HookHandler<DoubleClickElementEventArgs> DoubleClickElement; /// <summary> /// 注册元素监控,并指定是否立即监控. /// </summary> public static void Register(UIApplication uiApp, bool immediatelyMonitor = true) { if (uiApp == null) { throw new ArgumentNullException(nameof(uiApp)); } new ElementMonitor(uiApp) { m_IsMonitor = immediatelyMonitor }; } /// <summary> /// 注册元素监控,并指定是否立即监控. /// </summary> public static void Register(UIControlledApplication uiControllApp, bool immediatelyMonitor = true) { if (uiControllApp == null) { throw new ArgumentNullException(nameof(uiControllApp)); } var flag = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod; var uiApp = (UIApplication)uiControllApp.GetType().InvokeMember("getUIApplication", flag, Type.DefaultBinder, uiControllApp, null); Register(uiApp, immediatelyMonitor); } /// <summary> /// 返回1,则拦截鼠标消息,返回0则传递给真正消息接收者. /// </summary> private int OnRaiseMouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e) { if (!m_IsMonitor || e.Button != MouseButtons.Left || e.Clicks != 2) { return 0; } var uiDoc = m_UIApplication.ActiveUIDocument; if (uiDoc == null) { return 0; } var elemIds = uiDoc.Selection.GetElementIds(); if (elemIds.Count == 1) { var elem = uiDoc.Document.GetElement(elemIds.First()); if (elem == null) { return 0; } if (this.DoubleClickElement == null) { return 0; } return this.DoubleClickElement(this, new DoubleClickElementEventArgs(elem)); } return 0; } }
第五步,调用测试,如下
[Transaction(TransactionMode.Manual)] public class MouseHookTest : IExternalCommand { Result IExternalCommand.Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { if (ElementMonitor.Instance == null) { ElementMonitor.Register(commandData.Application); } ElementMonitor.Instance.DoubleClickElement += OnRaiseDoubleClickElement; return Result.Succeeded; } private int OnRaiseDoubleClickElement(object sender, DoubleClickElementEventArgs e) { if (e.Element == null) { return 0; } System.Windows.Forms.MessageBox.Show(string.Format("双击击元素Id: {0}", e.Element.Id)); return 1; } }
Github 源码 : https://github.com/HeZhongHao/DotNet.Revit/tree/master/DotNet.Revit/DotNet.Revit.Hook[/code]
相关文章推荐
- jQuery事件函数-点击、双击、键盘按键、鼠标滑动、失去焦点、显示哪个 DOM 元素触发了事件/返回事件的类型。等
- javascript中区分双击事件和鼠标按下事件
- DataGrid行随鼠标移动变色及单击双击行事件处理
- silverlight Canvas 捕获子元素的鼠标事件
- Vue 框架-02-事件:点击, 双击事件,鼠标移上事件
- 鼠标点击 INPUT 元素后默认触发的事件执行顺序
- QWidget标题栏双击事件(QWidget::event里拦截NonClientAreaMouseButtonDblClick)
- 使用jTopo给Html5 Canva中的元素添加鼠标事件
- IE和Chrome执行javascript对鼠标双击事件的不同响应
- GridView行 添加鼠标双击事件
- Unity 如何检测鼠标双击事件
- python+webdriver学习鼠标键盘事件以及定位元素
- 清除子元素继承父元素鼠标移入移出事件
- js鼠标双击的时候如何屏蔽单击事件呢
- 通过鼠标事件改变元素的某种状态
- JAVA中的鼠标双击事件收藏(转载)
- CListCtrl控件主要事件及LVN_ITEMCHANGED消息和鼠标双击列表项事件的处理
- c#使用钩子拦截鼠标键盘事件
- javascript事件列表大全解说,点击事件,双击事件,触发事件,键盘事件,鼠标移...
- javascript 鼠标单击和双击事件并存的实现方法