使用鉤子(Hook)實現Revit API中 PickObjects 完成按鈕的觸發

關注公衆號及時獲取文章更新

在實際的Revit 二次開發項目中,經常需要與Revit 模型元素進行交互,那麼除了藉助於過濾器來獲取對應元素之外,直接拾取元素(PickObjects 函數)也是常見的一種方式。然而在多選操作中,如果不是熟手,很容易找不到多選完成的按鈕(其位置見圖1,確實顯得不起眼)。

圖1

在Windows中,提供一種Hook機制,中文裏常常被譯作“鉤子”或者“掛鉤”,可以把Hook理解爲Windows操作系統消息處理機制的一個平臺;應用程序可以通過設置Hook對某個進程或窗口進行監視,即:對特定事件“掛鉤”;一旦預定義特定事件發生,Windows操作系統即會向鉤子hook發送通知消息,這時,應用程序可進行響應。

接下來我們來使用鉤子自動實現點擊多選操作中“完成”的按鈕!


目錄

Step 1  Step 2 Step 3Step 4Step 5Step 6 

問題

參考資料: 


 Step 1 

首先我們在NuGet 中安裝如圖的工具包(MouseKeyHook);

  Step 2

安裝各種鉤子;

    public static class WindowsHelper
    {
        [DllImport("user32.dll", CharSet = CharSet.None, ExactSpelling = false)]
        public static extern bool EnumChildWindows(IntPtr hwndParent, CallBack lpEnumFunc, IntPtr lParam);
        public delegate bool CallBack(IntPtr hwnd, int lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
        [DllImport("user32.dll", EntryPoint = "SendMessageA")]
        public static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, int lParam);
    }

 Step 3

註冊鼠標和鍵盤監視事件,作者添加了一個右鍵的鼠標事件和一個空格的鍵盤事件;

        public void Subscribe()
        {
            // Note: for the application hook, use the Hook.AppEvents() instead
            m_GlobalHook = Hook.GlobalEvents();
            m_GlobalHook.KeyUp += GlobalHookKeyUpExt;
            m_GlobalHook.MouseUpExt += GlobalHookMouseUpExt;
        }
        private void GlobalHookMouseUpExt(object sender, MouseEventExtArgs e)
        {
            if (e.Button == MouseButtons.Right) { CompleteMultiSelection(); }

        }
        private void GlobalHookKeyUpExt(object sender, KeyEventArgs e)
        {
            // 32 represent Space
            if (e.KeyValue == 32) { CompleteMultiSelection(); }

        }

Step 4

獲取Revit 主窗體下的所有句柄,找到“完成”按鈕併發送Click消息;

        private void CompleteMultiSelection()
        {
            var rvtWindow = Autodesk.Windows.ComponentManager.ApplicationWindow;
            var list = new List<IntPtr>();
            var flag = WindowsHelper.EnumChildWindows(rvtWindow,
                       (hwnd, l) =>
                       {
                           StringBuilder windowText = new StringBuilder(200);
                           WindowsHelper.GetWindowText(hwnd, windowText, windowText.Capacity);
                           StringBuilder className = new StringBuilder(200);
                           WindowsHelper.GetClassName(hwnd, className, className.Capacity);
                           if ((windowText.ToString().Equals("完成", StringComparison.Ordinal) ||
                          windowText.ToString().Equals("Finish", StringComparison.Ordinal)) &&
                          className.ToString().Contains("Button"))
                           {
                               list.Add(hwnd);
                               return false;
                           }
                           return true;
                       }, new IntPtr(0));

            var complete = list.FirstOrDefault();
            WindowsHelper.SendMessage(complete, 245, 0, 0);
        }

Step 5

註銷監視事件。

        public void Unsubscribe()
        {
            m_GlobalHook.MouseUpExt -= GlobalHookMouseUpExt;
            m_GlobalHook.KeyUp -= GlobalHookKeyUpExt;
            //It is recommened to dispose it
            m_GlobalHook.Dispose();
        }

Step 6 

功能測試! 

本測試程序的功能爲:獲取所選元素的IDs

問題

運行鉤子程序之後,圖2的區域的按鈕失效,無法關閉當前窗口,也無法實現ViewCube功能!

經多次嘗試,需右擊Revit模型顯示區域,點擊“取消”,即可恢復操作!

圖2

參考資料: 

鉤子讓PickObjects功力大增—BIMCoder樑老師

Revit二次開發番外篇之改變PickObjects完成按鈕的觸發

各個鍵盤按鍵KeyValue值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章