<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ZT文萃

    本博不原創(chuàng),轉(zhuǎn)帖自己感興趣那些事人物,什么入眼貼什么,隨心所欲。
    posts - 93, comments - 5, trackbacks - 0, articles - 0
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    C#鍵盤鉤子

    Posted on 2013-11-14 07:56 ZT文萃 閱讀(957) 評(píng)論(0)  編輯  收藏 所屬分類: 前臺(tái)
        本文由xyz8808貢獻(xiàn)
        2009-11-26 12:49//定義變量
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
        static int hKeyboardHook = 0;
        HookProc KeyboardHookProcedure;
        /*************************
        * 聲明API函數(shù)
        * ***********************/
        // 安裝鉤子 (using System.Runtime.InteropServices;)
        [DllImport("user32.dll",CharSet=CharSet.Auto, CallingC.StdCall)]
        public static extern int SetWindowsHookEx(int idHook,HookProc lpfn, IntPtr hInstance, int threadId);
        // 卸載鉤子
        [DllImport("user32.dll",CharSet=CharSet.Auto, CallingC.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
        // 繼續(xù)下一個(gè)鉤子
        [DllImport("user32.dll",CharSet=CharSet.Auto, CallingC.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
        // 取得當(dāng)前線程編號(hào)(線程鉤子需要用到)
        [DllImport("kernel32.dll")]
        static extern int GetCurrentThreadId();
        //鉤子子程:就是鉤子所要做的事情
        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
        if (nCode >= 0)
        {
        /****************
        //線程鍵盤鉤子判斷是否按下鍵
        Keys keyData = (Keys)wParam;
        if(lParam.ToInt32() > 0)
        {
        // 鍵盤按下
        }
        if(lParam.ToInt32() < 0)
        {
        // 鍵盤抬起
        }
        ****************/
        /****************
        //全局鍵盤鉤子判斷是否按下鍵
        wParam = = 0x100 // 鍵盤按下
        wParam = = 0x101 // 鍵盤抬起
        ****************/
        KeyMSG m = (KeyMSG) Marshal.PtrToStructure(lParam, typeof(KeyMSG));//鍵盤
        // 在這里添加你想要做是事情(比如把鍵盤nCode記錄下來(lái),搞個(gè)郵件發(fā)送程序發(fā)到自己的郵箱去)
        return 0;//如果返回1,則結(jié)束消息,這個(gè)消息到此為止,不再傳遞。如果返回0或調(diào)用CallNextHookEx函數(shù)則消息出了這個(gè)鉤子繼續(xù)往下傳遞,也就是傳給消息真正的接受者
        }
        return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
        }
        //鍵盤結(jié)構(gòu)
        public struct KeyMSG
        {
        public int vkCode; //鍵值
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
        }
        // 安裝鉤子
        public void HookStart()
        {
        if(hKeyboardHook == 0)
        {
        // 創(chuàng)建HookProc實(shí)例
        KeyboardHookProcedure = new HookProc(KeyboardHookProc);
        // 設(shè)置線程鉤子
        hKeyboardHook = SetWindowsHookEx( 13,KeyboardHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
        //************************************
        //鍵盤線程鉤子
        //SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId()); //GetCurrentThreadId()為要監(jiān)視的線程ID,你完全可以自己寫個(gè)方法獲取QQ的線程哦
        //鍵盤全局鉤子,需要引用空間(using System.Reflection;)
        //SetWindowsHookEx( 13,KeyboardHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
        //
        //關(guān)于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函數(shù)將鉤子加入到鉤子鏈表中,說(shuō)明一下四個(gè)參數(shù):
        //idHook 鉤子類型,即確定鉤子監(jiān)聽(tīng)何種消息,上面的代碼中設(shè)為2,即監(jiān)聽(tīng)鍵盤消息并且是線程鉤子,如果是全局鉤子監(jiān)聽(tīng)鍵盤消息應(yīng)設(shè)為13,
        //線程鉤子監(jiān)聽(tīng)鼠標(biāo)消息設(shè)為7,全局鉤子監(jiān)聽(tīng)鼠標(biāo)消息設(shè)為14。
        //
        //lpfn 鉤子子程的地址指針。如果dwThreadId參數(shù)為0 或是一個(gè)由別的進(jìn)程創(chuàng)建的線程的標(biāo)識(shí),lpfn必須指向DLL中的鉤子子程。 除此以外,lpfn可
        //以指向當(dāng)前進(jìn)程的一段鉤子子程代碼。鉤子函數(shù)的入口地址,當(dāng)鉤子鉤到任何消息后便調(diào)用這個(gè)函數(shù)。
        //
        //hInstance應(yīng)用程序?qū)嵗木浔?biāo)識(shí)包含lpfn所指的子程的DLL。如果threadId 標(biāo)識(shí)當(dāng)前進(jìn)程創(chuàng)建的一個(gè)線程,而且子程代碼位于當(dāng)前
        //進(jìn)程,hInstance必須為NULL。可以很簡(jiǎn)單的設(shè)定其為本應(yīng)用程序的實(shí)例句柄。
        //
        //threadedId 與安裝的鉤子子程相關(guān)聯(lián)的線程的標(biāo)識(shí)符。如果為0,鉤子子程與所有的線程關(guān)聯(lián),即為全局鉤子。
        //************************************
        // 如果設(shè)置鉤子失敗
        if(hKeyboardHook == 0 )
        {
        HookStop();
        throw new Exception("SetWindowsHookEx failed.");
        }
        }
        }
        // 卸載鉤子
        public void HookStop()
        {
        bool retKeyboard = true;
        if(hKeyboardHook != 0)
        {
        retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
        hKeyboardHook = 0;
        }
        if (!( retKeyboard))
        throw new Exception("UnhookWindowsHookEx failed.");
        }
        //*****************************
        試用了一下,不是很穩(wěn)定,改回自帶的 KeyUp函數(shù)了,記錄以備查
        //自定義類型
        public enum HookType
        {
        WH_KEYBOARD = 2
        }
        public delegate int HOOKPROC(int nCode, int wParam, int lParam);
        //接口調(diào)用
        [DllImport( "User32.DLL ")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg,int wParam,int lParam);
        [DllImport("kernel32")]
        public static extern int GetCurrentThreadId();
        [DllImport("User32.Dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport( "user32",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(HookType idHook,HOOKPROC lpfn,int hmod,int dwThreadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto,CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode,int wParam,int lParam);
        //函數(shù)實(shí)現(xiàn)
        public void SetHook()
        {
        SetWindowsHookEx(HookType.WH_KEYBOARD,
        new HOOKPROC(this.MyKeyboardProc),
        0,
        GetCurrentThreadId());
        }
        public int MyKeyboardProc(int nCode, int wParam, int lParam)
        {
        IntPtr ParenthWnd = new IntPtr(0);
        bool isPressed = (((lParam & 0x80000000) == 0) && (nCode==0));
        CallNextHookEx(m_HookHandle, nCode, wParam, lParam); //先把消息發(fā)給系統(tǒng)默認(rèn)處理隊(duì)列
        global.lastKeyValue = wParam;
        ParenthWnd = FindWindow( null,"零售業(yè)務(wù)");
        switch(wParam)
        {
        case 112: //修改數(shù)量 F1
        if(isPressed)
        {
        inputType = global.ST_NUM_STP1;
        doKeyWork();
        }
        break;
        case 113: //備注 F2
        if(isPressed)
        {
        inputType = global.ST_REMARK;
        textBoxBZ.Focus();
        textBoxBZ.SelectAll();
        }
        break;
        case 114: //摘要 F3
        if(isPressed)
        {
        inputType = global.ST_ABST;
        textBoxZY.Focus();
        textBoxZY.SelectAll();
        }
        break;
        case 115: //支付 F4
        if(isPressed)
        if((global.saleList == null) || (global.saleList.Length == 0))
        break;
        else
        {
        showProductInfo();
        labelCPZS.Text = global.sAllNum.ToString() + " 件";
        labelYSJE.Text = global.sAllValue.ToString() + " 元";
        labelYHJE.Text = global.sPriValue.ToString() + " 元";
        labelSSJE.Text = global.sDueValue.ToString() + " 元";
        inputType = global.ST_GATHER_STP1;
        textBoxSK.Focus();
        textBoxSK.SelectAll();
        }
        break;
        case 116: //輸入產(chǎn)品 F5
        if(isPressed)
        {
        inputType = global.ST_PRODUCT;
        textBoxSPMC.Focus();
        textBoxSPMC.SelectAll();
        }
        break;
        case 117: //開(kāi)始新訂單 F6
        if(isPressed)
        {
        resetSale(); //銷售界面復(fù)位
        }
        break;
        default:
        //CallNextHookEx(m_HookHandle, nCode, wParam, lParam);
        break;
        }
        return(0);
        }
        ///
        /// 清理所有正在使用的資源。
        ///
        protected override void Dispose( bool disposing )
        {
        if( disposing )
        {
        if(components != null)
        {
        components.Dispose();
        }
        }
        base.Dispose( disposing );
        }
        C#中鍵盤鉤子的使用
        默認(rèn)分類 2008-07-05 17:33 閱讀53 評(píng)論0 字號(hào): 大大 中中 小小 public class Win32Hook
        {
        [DllImport("kernel32")]
        public static extern int GetCurrentThreadId();
        [DllImport( "user32",
        CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(
        HookType idHook,
        HOOKPROC lpfn,
        int hmod,
        int dwThreadId);
        public enum HookType
        {
        WH_KEYBOARD = 2
        }
        public delegate int HOOKPROC(int nCode, int wParam, int lParam);
        public void SetHook()
        {
        // set the keyboard hook
        SetWindowsHookEx(HookType.WH_KEYBOARD,
        new HOOKPROC(this.MyKeyboardProc),
        0,
        GetCurrentThreadId());
        }
        public int MyKeyboardProc(int nCode, int wParam, int lParam)
        {
        //在這里放置你的處理代碼 return 0;
        }
        }
        使用方法
        可以在Form的構(gòu)造函數(shù)里放入
        Win32Hook hook = new Win32Hook();
        hook.SetHook();
        C#+低級(jí)Windows API鉤子攔截鍵盤輸入
        www.diybl.com 時(shí)間:2010-01-14 作者:匿名 編輯:Smi1e 點(diǎn)擊: 9 [評(píng)論]
        -
        -
        摘要 在家里,嬰兒和其它動(dòng)物可能會(huì)重?fù)裟愕挠?jì)算機(jī)鍵盤,致使出現(xiàn)各種無(wú)法預(yù)言的結(jié)果。本文中的這個(gè)C#示例應(yīng)用程序?qū)⑾蚰阏故救绾位赪indows鉤子API來(lái)實(shí)現(xiàn)在擊鍵造成任何危害之前捕獲它們。
        一. 簡(jiǎn)介
        貓和嬰兒有很多共同之處。他們都喜歡吃家中養(yǎng)植的植物,都非常討厭關(guān)門。他們也都愛(ài)玩弄你的鍵盤,結(jié)果是,你正發(fā)送給你的老板的電子郵件可能是以半截句子發(fā)送出去的,你的Excel帳戶也被加入了一些亂七八糟的內(nèi)容,并且你還沒(méi)有注意到,當(dāng)打開(kāi)Windows資源管理器時(shí),若干文件已經(jīng)被移到了回收站!
        其解決方案是,開(kāi)發(fā)一個(gè)應(yīng)用程序?qū)崿F(xiàn)如下功能:只要鍵盤處于"威脅狀態(tài)"你就可以進(jìn)行切換,并確保任何鍵盤輸入活動(dòng)都不會(huì)造成危害。本文想展示如何使用一種低級(jí)Windows API鉤子在一個(gè)C#應(yīng)用程序中實(shí)現(xiàn)鍵盤"控制"。下圖是本文示例程序的一個(gè)運(yùn)行快照。
        二. 背景
        其實(shí),已經(jīng)存在許多有關(guān)于Windows鉤子的文章和示例代碼,并且已經(jīng)有人編寫過(guò)與本文幾乎一樣的C++示例程序。然而,當(dāng)我搜索相應(yīng)的C#應(yīng)用程序的源碼時(shí),卻找到極少的.NET示例,而且沒(méi)有一個(gè)程序能夠提供一個(gè)方便的自包含的C#類。
        .NET框架能夠使你以托管方式來(lái)存取你最常使用的鍵盤事件(通過(guò)KeyPress,KeyUp和KeyDown)。遺憾的是,這些事件都不能被用來(lái)停止Windows組合鍵(如Alt+Tab或Windows"開(kāi)始"鍵),從而允許用戶"遠(yuǎn)離"某一個(gè)應(yīng)用程序。
        本文的想法在操作系統(tǒng)級(jí)上捕獲鍵盤事件而不是通過(guò)框架級(jí)來(lái)實(shí)現(xiàn)。為此,應(yīng)用程序需要使用Windows API函數(shù)來(lái)把它自身添加到應(yīng)用程序"鉤子鏈"中以監(jiān)聽(tīng)來(lái)自操作系統(tǒng)的鍵盤消息。當(dāng)它收到這種類型的消息時(shí),該應(yīng)用程序能夠選擇性地傳遞消息,或者進(jìn)行正常處理,或者"鎮(zhèn)壓"它以便不再有其它應(yīng)用程序(包括Windows)來(lái)影響它。本文正是想解釋其實(shí)現(xiàn)機(jī)理。
        然而,請(qǐng)注意,本文中的代碼僅適用于基于NT版本的Windows(NT,2000和XP),并且無(wú)法使用這個(gè)方法來(lái)停用Ctrl+Alt+Delete。有關(guān)于如何實(shí)現(xiàn)這一點(diǎn),你可以參考MSDN有關(guān)資料。
        三. 使用代碼
        為了易于使用,我在本文中提供了兩個(gè)獨(dú)立的zip文件。一個(gè)僅包含KeyboardHook類,這是本文介紹的重點(diǎn)。另一個(gè)是一個(gè)完整的微軟Visual C# 2005 Express Edition應(yīng)用程序工程,名叫"Baby Keyboard Bash",它實(shí)現(xiàn)顯示擊鍵的名字或彩色的形狀以響應(yīng)于擊鍵。
        四. 實(shí)例化類
        鍵盤鉤子是通過(guò)keyboard.cs中的KeyboardHook類來(lái)建立和管理的。這個(gè)類實(shí)現(xiàn)了IDisposable接口,因此,實(shí)例化它的最簡(jiǎn)單的方法是在應(yīng)用程序的Main()方法中使用using關(guān)鍵字來(lái)封裝Application.Run()調(diào)用。這將確保只要該應(yīng)用程序開(kāi)始即建立鉤子并且,更重要的是,當(dāng)該應(yīng)用程序結(jié)束時(shí)立即使這個(gè)鉤子失效。
        這個(gè)類引發(fā)一個(gè)事件來(lái)警告應(yīng)用程序已經(jīng)有鍵被按下,因此主表單能夠存取在Main()方法中創(chuàng)建的KeyboardHook實(shí)例就顯得非常重要;最簡(jiǎn)單的方法是把這個(gè)實(shí)例存儲(chǔ)在一個(gè)公共成員變量中。
        KeyboardHook提供了三種構(gòu)造器來(lái)啟用或禁用某些設(shè)置:
        · KeyboardHook():捕獲所有擊鍵,沒(méi)有任何內(nèi)容傳遞到Windows或另外的應(yīng)用程序。
        · KeyboardHook(string param):把參數(shù)串轉(zhuǎn)換為Parameters枚舉中的值之一,然后調(diào)用下面的構(gòu)造器:
        · KeyboardHook(KeyboardHook.Parameters enum):根據(jù)從Parameters枚舉中選擇的值的不同,分別啟動(dòng)下列設(shè)置:
        o Parameters.AllowAltTab:允許用戶使用Alt+Tab切換到另外的應(yīng)用程序。
        o Parameters.AllowWindowsKey:允許用戶使用Ctrl+Esc或一種Windows鍵存取任務(wù)欄和開(kāi)始菜單。
        o Parameters.AllowAltTabAndWindows:?jiǎn)⒂肁lt+Tab,Ctrl+Esc和Windows鍵。
        o Parameters.PassAllKeysToNextApp:如果該參數(shù)為true,那么所有的擊鍵將被傳遞給任何其它監(jiān)聽(tīng)?wèi)?yīng)用程序(包括Windows)。
        當(dāng)擊鍵繼續(xù)被鍵盤鉤子捕獲時(shí),啟用Alt+Tab和/或Windows鍵允許實(shí)際使用該計(jì)算機(jī)者切換到另一個(gè)應(yīng)用程序并且使用鼠標(biāo)與之交互。PassAllKeysToNextApp設(shè)置有效地禁用了擊鍵捕獲;這個(gè)類也是建立一個(gè)低級(jí)鍵盤鉤子并且引發(fā)它的KeyIntercepted事件,但是它還負(fù)責(zé)把鍵盤事件傳遞到另一個(gè)監(jiān)聽(tīng)程序。
        因此,實(shí)例化該類以捕獲所有擊鍵的方法如下:
        public static KeyboardHook kh;
        [STAThread]
        static void Main()
        {
        //其它代碼
        using (kh = new KeyboardHook())
        {
        Application.Run(new Form1());
        }
        五. 處理KeyIntercepted事件
        當(dāng)一外鍵被按下時(shí),這個(gè)KeyboardHook類激活一個(gè)包含一些KeyboardHookEventArgs的KeyIntercepted事件。這是通過(guò)一個(gè)KeyboardHookEventHandler類型的方法使用以下方式來(lái)實(shí)現(xiàn)的:
        kh.KeyIntercepted += new KeyboardHook.KeyboardHookEventHandler(kh_KeyIntercepted);
        這個(gè)KeyboardHookEventArgs返回關(guān)于被按下鍵的下列信息:
        · KeyName:鍵名,通過(guò)把捕獲的鍵代碼強(qiáng)制轉(zhuǎn)換為System.Windows.Forms.Keys而獲得。
        · KeyCode:由鍵盤鉤子返回的原來(lái)的鍵代碼
        · PassThrough:指出是否這個(gè)KeyboardHook實(shí)例被配置以允許該擊鍵傳遞到其它應(yīng)用程序。如果你想允許一用戶使用Alt+Tab或 Ctrl+Esc/Windows鍵切換到其它的應(yīng)用程序的話,那么對(duì)之進(jìn)行檢查是很有用的。
        然后,使用一個(gè)具有適當(dāng)簽名的方法來(lái)執(zhí)行擊鍵所調(diào)用的任何任務(wù)。下面是一個(gè)示例片斷:
        void kh_KeyIntercepted(KeyboardHookEventArgs e)
        {
        //檢查是否這個(gè)鍵擊事件被傳遞到其它應(yīng)用程序并且停用TopMost,以防他們需要調(diào)到前端
        if (e.PassThrough)
        {
        this.TopMost = false;
        }
        ds.Draw(e.KeyName);
        }
        本文的剩下部分將解釋低級(jí)鍵盤鉤子是如何在KeyboardHook中實(shí)現(xiàn)的。
        六. 實(shí)現(xiàn)一個(gè)低級(jí)Windows API鍵盤鉤子
        在user32.dll中,Windows API包含三個(gè)方法來(lái)實(shí)現(xiàn)此目的:
        · SetWindowsHookEx,它負(fù)責(zé)建立鍵盤鉤子
        · UnhookWindowsHookEx,它負(fù)責(zé)移去鍵盤鉤子
        · CallNextHookEx,它負(fù)責(zé)把擊鍵信息傳遞到下一個(gè)監(jiān)聽(tīng)鍵盤事件的應(yīng)用程序
        創(chuàng)建一個(gè)能夠攔截鍵盤的應(yīng)用程序的關(guān)鍵是,實(shí)現(xiàn)前面兩個(gè)方法,而"放棄"第三個(gè)。結(jié)果是,任何擊鍵都只能傳遞到這個(gè)應(yīng)用程序中。
        為了實(shí)現(xiàn)這一目標(biāo),第一步是包括System.Runtime.InteropServices命名空間并且導(dǎo)入API方法,首先是SetWindowsHookEx:
        using System.Runtime.InteropServices
        ……
        //在類內(nèi)部:
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
        LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
        導(dǎo)入U(xiǎn)nhookWindowsHookEx和CallNextHookEx的代碼請(qǐng)見(jiàn)后面的討論。
        下一步是調(diào)用SetWindowsHookEx來(lái)建立鉤子,這時(shí)需要傳遞下列四個(gè)參數(shù):
        · idHook:
        這個(gè)數(shù)字決定了要建立的鉤子的類型。例如,SetWindowsHookEx可以被用于鉤住鼠標(biāo)事件(當(dāng)然還有其它事件)。在本文情況下,我們僅對(duì)13有興趣,這是鍵盤鉤子的id。為了使代碼更易讀些,我們把它賦值給一個(gè)常數(shù)WH_KEYBOARD_LL。
        · Lpfn:
        這是一個(gè)指向函數(shù)的長(zhǎng)指針,該函數(shù)將負(fù)責(zé)處理鍵盤事件。在C#中,"指針"是通過(guò)傳遞一個(gè)代理類型的實(shí)例而獲得的,從而使之引用一個(gè)適當(dāng)?shù)姆椒ā_@是我們?cè)诿看问褂勉^子時(shí)所調(diào)用的方法。
        這里值得注意的是,這個(gè)代理實(shí)例需要被存儲(chǔ)于這個(gè)類的一個(gè)成員變量中。這是為了防止一旦第一個(gè)方法調(diào)用結(jié)束它會(huì)被作為垃圾回收。
        · hMod:
        建立鉤子的應(yīng)用程序的一個(gè)實(shí)例句柄。我找到的絕大多數(shù)實(shí)例僅把它設(shè)置為IntPtr.Zero,理由是不大可能存在該應(yīng)用程序的多個(gè)實(shí)例。然而,這部分代碼使用了來(lái)自于kernel32.dll的GetModuleHandle來(lái)標(biāo)識(shí)準(zhǔn)確的實(shí)例從而使這個(gè)類更具靈活性。
        · dwThreadId:
        當(dāng)前進(jìn)程的id。把它設(shè)置為0可以使這個(gè)鉤子成為全局構(gòu)子,這是相應(yīng)于一個(gè)低級(jí)鍵盤鉤子的正確設(shè)置。
        SetWindowsHookEx返回一個(gè)鉤子id,這個(gè)id將被用于當(dāng)應(yīng)用程序結(jié)束時(shí)從鉤子鏈中脫鉤,因此它需要存儲(chǔ)在一個(gè)成員變量中以備將來(lái)使用。KeyboardHook類中的相關(guān)代碼如下:
        private HookHandlerDelegate proc;
        private IntPtr hookID = IntPtr.Zero;
        private const int WH_KEYBOARD_LL = 13;
        public KeyboardHook()
        {
        proc = new HookHandlerDelegate(HookCallback);
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
        hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc,GetModuleHandle(curModule.ModuleName), 0);
        }
        }
        七. 處理鍵盤事件
        如前面所提及,SetWindowsHookEx需要一個(gè)到被用來(lái)處理鍵盤事件的回調(diào)函數(shù)的指針。它期望有一個(gè)使用如下簽名的函數(shù):
        LRESULT CALLBACK LowLevelKeyboardProc( int nCode,WPARAM wParam,LPARAM lParam);
        其實(shí),建立一個(gè)函數(shù)指針的C#方法使用了一個(gè)代理,因此,向SetWindowsHookEx指出它需要的內(nèi)容的第一步是使用正確的簽名來(lái)聲明一個(gè)代理:
        private delegate IntPtr HookHandlerDelegate(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
        然后,使用相同的簽名編寫一個(gè)回調(diào)方法;這個(gè)方法將包含實(shí)際上處理鍵盤事件的所有代碼。在KeyboardHook的情況下,它檢查是否擊鍵應(yīng)該被傳遞給其它應(yīng)用程序并且接下來(lái)激發(fā)KeyIntercepted事件。下面是一個(gè)簡(jiǎn)化版本的不帶有擊鍵處理代碼的情況:
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;
        private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
        {
        //僅為KeyDown事件過(guò)濾wParam,否則該代碼將再次執(zhí)行-對(duì)于每一次擊鍵(也就是,相應(yīng)于KeyDown和KeyUp)
        //WM_SYSKEYDOWN是捕獲Alt相關(guān)組合鍵所必需的
        if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
        {
        //激發(fā)事件
        OnKeyIntercepted(new KeyboardHookEventArgs(lParam.vkCode, AllowKey));
        //返回一個(gè)"啞"值以捕獲擊鍵
        return (System.IntPtr)1;
        }
        //事件沒(méi)有被處理,把它傳遞給下一個(gè)應(yīng)用程序
        return CallNextHookEx(hookID, nCode, wParam, ref lParam);
        }
        接下來(lái),一個(gè)到HookCallback的參考被指派給HookHandlerDelegate的一個(gè)實(shí)例并且被傳遞到SetWindowsHookEx的調(diào)用,正如前一節(jié)所展示的。
        無(wú)論何時(shí)一個(gè)鍵盤事件發(fā)生,下列參數(shù)將被傳遞給HookCallBack:
        · nCode:
        根據(jù)MSDN文檔,回調(diào)函數(shù)應(yīng)該返回CallNextHookEx的結(jié)果,如果這個(gè)值小于零的話。正常的鍵盤事件將返回一個(gè)大于或等于零的nCode值。
        · wParam:
        這個(gè)值指示發(fā)生了什么類型的事件:鍵被按下還是松開(kāi),以及是否按下的鍵是一個(gè)系統(tǒng)鍵(左邊或右邊的Alt鍵)。
        · lParam:
        這是一個(gè)存儲(chǔ)精確擊鍵信息的結(jié)構(gòu),例如被按鍵的代碼。在KeyboardHook中聲明的這個(gè)結(jié)構(gòu)如下:
        private struct KBDLLHOOKSTRUCT
        {
        public int vkCode;
        int scanCode;
        public int flags;
        int time;
        int dwExtraInfo;
        }
        其中的這兩個(gè)公共參數(shù)是在KeyboardHook中的回調(diào)方法所使用的僅有的兩個(gè)參數(shù)。vkCoke返回虛擬鍵代碼,它能夠被強(qiáng)制轉(zhuǎn)換為System.Windows.Forms.Keys以獲得鍵名,而flags顯示是否這是一個(gè)擴(kuò)展鍵(例如,Windows Start鍵)或是否同時(shí)按下了Alt鍵。有關(guān)于Hook回調(diào)方法的完整代碼展示在每一種情況下要檢查哪些flags值。
        如果flags提供的信息和KBDLLHOOKSTRUCT的其它組成元素不需要,那么這個(gè)回調(diào)方法和代碼的簽名可以按如下進(jìn)行修改:
        private delegate IntPtr HookHandlerDelegate(
        int nCode, IntPtr wParam, IntPtr lParam);
        在這種情況中,lParam將僅返回vkCode。
        八. 把擊鍵傳遞到下一個(gè)應(yīng)用程序
        一個(gè)良好的鍵盤鉤子回調(diào)方法應(yīng)該以調(diào)用CallNextHookEx函數(shù)并且返回它的結(jié)果結(jié)束。這可以確保其它應(yīng)用程序能夠有機(jī)會(huì)處理針對(duì)于它們的擊鍵。
        然而,KeyboardHook類的主要功能在于,阻止擊鍵被傳播到任何其它更多的應(yīng)用程序。因此它無(wú)論在何時(shí)處理一次擊鍵,HookCallback都將返回一個(gè)啞值:
        return (System.IntPtr)1;
        另一方面,它確實(shí)調(diào)用CallNextHookEx-如果它不處理該事件,或如果重載的構(gòu)造器中的使用KeyboardHook傳遞的參數(shù)允許某些組合鍵通過(guò)。
        CallNextHookEx被啟用-通過(guò)從user32.dll導(dǎo)入該函數(shù),如下列代碼所示:
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private
        static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        IntPtr wParam, ref KeyInfoStruct lParam);
        然后,被導(dǎo)入的方法被HookCallMethod所調(diào)用,這可以確保所有的通過(guò)鉤子接收到的參數(shù)被繼續(xù)傳遞到下一個(gè)應(yīng)用程序中:
        CallNextHookEx(hookID, nCode, wParam, ref lParam);
        如前面所提及,如果在lParam中的flags是不相關(guān)的,那么可以修改導(dǎo)入的CallNextHookEx的簽名以把lParam定義為System.IntPtr。
        九. 移去鉤子
        處理鉤子的最后一步是使用從user32.dll中導(dǎo)入的UnhookWindowsHookEx函數(shù)移去它(當(dāng)破壞KeyboardHook類的實(shí)例時(shí)),如下所示:
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
        既然KeyboardHook實(shí)現(xiàn)IDisposable,那么這可以在Dispose方法中完成。
        public void Dispose()
        {
        UnhookWindowsHookEx(hookID);
        }
        hookID是構(gòu)造器在調(diào)用SetWindowsHookEx所返回的id。這將從鉤子鏈中刪除應(yīng)用程序。
        c#鍵盤鉤子
        作者: lzh 類別: C#/VB 日期: 2003-5-27 22:22:19
        You can use system hook to hook any messages send to the application.
        Hooking the keyboard (WH_KEYBOARD) and mouse (WH_MOUSE) messages can be
        used to determine if the user interactive with the computer. You also can
        hook all the messages (WH_GETMESSAGE). The hook can be set with this code:
        public class Win32Hook
        {
        [DllImport("kernel32")]
        public static extern int GetCurrentThreadId();
        [DllImport( "user32",
        CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(
        HookType idHook,
        HOOKPROC lpfn,
        int hmod,
        int dwThreadId);
        public enum HookType
        {
        WH_GETMESSAGE = 3
        }
        public delegate int HOOKPROC(int nCode, int wParam, int lParam);
        public void SetHook()
        {
        // set the keyboard hook
        SetWindowsHookEx(HookType.WH_GETMESSAGE,
        new HOOKPROC(this.MyKeyboardProc),
        0,
        GetCurrentThreadId());
        }
        public int MyKeyboardProc(int nCode, int wParam, int lParam)
        {
        //Perform your process
        return 0;
        }
        }
        Then you can install the hook procedure by the following code:
        Win32Hook hook = new Win32Hook();
        hook.SetHook();
        用鉤子(hook)實(shí)現(xiàn)C#的屏幕鍵盤效果
        -
        SVN技術(shù)網(wǎng) www.svn8.com 2010-01-20 08:38:02 來(lái)源:bbs.svn8.com 作者:佚名 點(diǎn)擊:158次
        文章摘要:用鉤子(hook)實(shí)現(xiàn)C#的屏幕鍵盤效果 要實(shí)現(xiàn)一個(gè)屏幕鍵盤,需要監(jiān)聽(tīng)所有鍵盤事件,無(wú)論窗體是否被激活。因此需要一個(gè)全局的鉤子,也就 是系統(tǒng)范圍的鉤子。 什么是鉤子(Hook) 鉤子(Hook)是Windows提供的一種消息處理機(jī)制平臺(tái),是指在程序正常運(yùn)行中接受信息之前預(yù)先啟動(dòng)的函數(shù),用來(lái)檢查和修改傳給該程序的信息,(鉤子)
        -
        使用完鉤子后,要進(jìn)行卸載,這個(gè)可以寫在析構(gòu)函數(shù)中。
        12 public void Stop() {3 this.Stop(true, true, true);4 }5 6 public void Stop(bool uninstallMouseHook, bool uninstallKeyboardHook, 7 bool throwExceptions) {8 // if mouse hook set and must be uninstalled9 if (hMouseHook != IntPtr.Zero && uninstallMouseHook) {10 // uninstall hook11 bool retMouse = UnhookWindowsHookEx(hMouseHook);12 // reset invalid handle13 hMouseHook = IntPtr.Zero;14 // if failed and exception must be thrown15 if (retMouse == false && throwExceptions) {16 // Returns the error code returned by the last unmanaged function 17 // called using platform invoke that has the DllImportAttribute.18 // SetLastError flag set. 19 int errorCode = Marshal.GetLastWin32Error();20 // Initializes and throws a new instance of the Win32Exception class 21 // with the specified error. 22 throw new Win32Exception(errorCode);23 }24 }2526 // if keyboard hook set and must be uninstalled27 if (hKeyboardHook != IntPtr.Zero && uninstallKeyboardHook) {28 // uninstall hook29 bool retKeyboard = UnhookWindowsHookEx(hKeyboardHook);30 // reset invalid handle31 hKeyboardHook = IntPtr.Zero;32 // if failed and exception must be thrown33 if (retKeyboard == false && throwExceptions) {34 // Returns the error code returned by the last unmanaged function 35 // called using platform invoke that has the DllImportAttribute.36 // SetLastError flag set. 37 int errorCode = Marshal.GetLastWin32Error();38 // Initializes and throws a new instance of the Win32Exception class 39 // with the specified error. 40 throw new Win32Exception(errorCode);41 }42 }43 }44
        將這個(gè)文件編譯成一個(gè)dll,即可在應(yīng)用程序中調(diào)用。通過(guò)它提供的事件,便可監(jiān)聽(tīng)所有的鍵盤事件。
        但是,這只能監(jiān)聽(tīng)鍵盤事件,沒(méi)有鍵盤的情況下,怎么會(huì)有鍵盤事件?其實(shí)很簡(jiǎn)單,通過(guò)SendInput
        API函數(shù)提供虛擬鍵盤代碼的調(diào)用即可模擬鍵盤輸入。下面的代碼模擬一個(gè) KeyDown 和 KeyUp 過(guò)程,
        把他們連接起來(lái)就是一次按鍵過(guò)程。
        1 private void SendKeyDown(short key) {2 Input[] input = new Input[1];3 input[0].type = INPUT.KEYBOARD;4 input[0].ki.wVk = key;5 input[0].ki.time = NativeMethods.GetTickCount();67 if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) 8 < input.Length) {9 throw new Win32Exception(Marshal.GetLastWin32Error());10 }11 }1213 private void SendKeyUp(short key) {14 Input[] input = new Input[1];15 input[0].type = INPUT.KEYBOARD;16 input[0].ki.wVk = key;17 input[0].ki.dwFlags = KeyboardConstaint.KEYEVENTF_KEYUP;18 input[0].ki.time = NativeMethods.GetTickCount();1920 if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0]))21 < input.Length) {22 throw new Win32Exception(Marshal.GetLastWin32Error());23 }24 }
        自己實(shí)現(xiàn)一個(gè) KeyBoardButton 控件用作按鈕,用 Visual Studio 或者 SharpDevelop 為屏幕鍵盤設(shè)計(jì) UI,然后
        在這些 Button 的 Click 事件里面模擬一個(gè)按鍵過(guò)程。
        12 private void ButtonOnClick(object sender, EventArgs e) {3 KeyboardButton btnKey = sender as KeyboardButton;4 if (btnKey == null) {5 return;6 }78 SendKeyCommand(btnKey);9 }10 11 private void SendKeyCommand(KeyboardButton keyButton) {12 short key = keyButton.VKCode;13 if (combinationVKButtonsMap.ContainsKey(key)) {14 if (keyButton.Checked) {15 SendKeyUp(key);16 } else {17 SendKeyDown(key);18 }19 } else {20 SendKeyDown(key);21 SendKeyUp(key);22 }23 }
        其中 combinationVKButtonsMap 是一個(gè) IDictionary>, key 存儲(chǔ)的是VK_SHIFT, VK_CONTROL 等組合鍵的鍵盤碼。左右兩個(gè)按鈕對(duì)應(yīng)同一個(gè)鍵盤碼,因此需要放在一個(gè) List 里。
        標(biāo)準(zhǔn)鍵盤上的每一個(gè)鍵都有虛擬鍵碼( VK_CODE)與之對(duì)應(yīng)。還有一些其他的常量,
        把它寫在一個(gè)靜態(tài) class 里吧。
        1 // KeyboardConstaint.cs2 internal static class KeyboardConstaint {3 internal static readonly short VK_F1 = 0x70;4 internal static readonly short VK_F2 = 0x71;5 internal static readonly short VK_F3 = 0x72;6 internal static readonly short VK_F4 = 0x73;7 internal static readonly short VK_F5 = 0x74;8 internal static readonly short VK_F6 = 0x75;9 internal static readonly short VK_F7 = 0x76;10 internal static readonly short VK_F8 = 0x77;11 internal static readonly short VK_F9 = 0x78;12 internal static readonly short VK_F10 = 0x79;13 internal static readonly short VK_F11 = 0x7A;14 internal static readonly short VK_F12 = 0x7B;1516 internal static readonly short VK_LEFT = 0x25;17 internal static readonly short VK_UP = 0x26;18 internal static readonly short VK_RIGHT = 0x27;19 internal static readonly short VK_DOWN = 0x28;2021 internal static readonly short VK_NONE = 0x00;22 internal static readonly short VK_ESCAPE = 0x1B;23 internal static readonly short VK_EXECUTE = 0x2B;24 internal static readonly short VK_CANCEL = 0x03;25 internal static readonly short VK_RETURN = 0x0D;26 internal static readonly short VK_ACCEPT = 0x1E;27 internal static readonly short VK_BACK = 0x08;28 internal static readonly short VK_TAB = 0x09;29 internal static readonly short VK_DELETE = 0x2E;30 internal static readonly short VK_CAPITAL = 0x14;31 internal static readonly short VK_NUMLOCK = 0x90;32 internal static readonly short VK_SPACE = 0x20;33 internal static readonly short VK_DECIMAL = 0x6E;34 internal static readonly short VK_SUBTRACT = 0x6D;3536 internal static readonly short VK_ADD = 0x6B;37 internal static readonly short VK_DIVIDE = 0x6F;38 internal static readonly short VK_MULTIPLY = 0x6A;39 internal static readonly short VK_INSERT = 0x2D;4041 internal static readonly short VK_OEM_1 = 0xBA; // ';:' for US42 internal static readonly short VK_OEM_PLUS = 0xBB; // '+' any country4344 internal static readonly short VK_OEM_MINUS = 0xBD; // '-' any country4546 internal static readonly short VK_OEM_2 = 0xBF; // '/?' for US47 internal static readonly short VK_OEM_3 = 0xC0; // '`~' for US48 internal static readonly short VK_OEM_4 = 0xDB; // '[{' for US49 internal static readonly short VK_OEM_5 = 0xDC; // '\|' for US50 internal static readonly short VK_OEM_6 = 0xDD; // ']}' for US51 internal static readonly short VK_OEM_7 = 0xDE; // ''"' for US52 internal static readonly short VK_OEM_PERIOD = 0xBE; // '.>' any country53 internal static readonly short VK_OEM_COMMA = 0xBC; // ',<' any country54 internal static readonly short VK_SHIFT = 0x10;55 internal static readonly short VK_CONTROL = 0x11;56 internal static readonly short VK_MENU = 0x12;57 internal static readonly short VK_LWIN = 0x5B;58 internal static readonly short VK_RWIN = 0x5C;59 internal static readonly short VK_APPS = 0x5D;6061 internal static readonly short VK_LSHIFT = 0xA0;62 internal static readonly short VK_RSHIFT = 0xA1;63 internal static readonly short VK_LCONTROL = 0xA2;64 internal static readonly short VK_RCONTROL = 0xA3;65 internal static readonly short VK_LMENU = 0xA4;66 internal static readonly short VK_RMENU = 0xA5;6768 internal static readonly short VK_SNAPSHOT = 0x2C;69 internal static readonly short VK_SCROLL = 0x91;70 internal static readonly short VK_PAUSE = 0x13;71 internal static readonly short VK_HOME = 0x24;7273 internal static readonly short VK_NEXT = 0x22;74 internal static readonly short VK_PRIOR = 0x21;75 internal static readonly short VK_END = 0x23;7677 internal static readonly short VK_NUMPAD0 = 0x60;78 internal static readonly short VK_NUMPAD1 = 0x61;79 internal static readonly short VK_NUMPAD2 = 0x62;80 internal static readonly short VK_NUMPAD3 = 0x63;81 internal static readonly short VK_NUMPAD4 = 0x64;82 internal static readonly short VK_NUMPAD5 = 0x65;83 internal static readonly short VK_NUMPAD5NOTHING = 0x0C;84 internal static readonly short VK_NUMPAD6 = 0x66;85 internal static readonly short VK_NUMPAD7 = 0x67;86 internal static readonly short VK_NUMPAD8 = 0x68;87 internal static readonly short VK_NUMPAD9 = 0x69;8889 internal static readonly short KEYEVENTF_EXTENDEDKEY = 0x0001;90 internal static readonly short KEYEVENTF_KEYUP = 0x0002;9192 internal static readonly int GWL_EXSTYLE = -20;93 internal static readonly int WS_DISABLED = 0X8000000;94 internal static readonly int WM_SETFOCUS = 0X0007;95 }
        文章來(lái)自[SVN中文技術(shù)網(wǎng)]轉(zhuǎn)發(fā)請(qǐng)保留本站地址:http://www.svn8.com/dotnet/Csharp/2010012018328_2.html
        C#中鍵盤鉤子的使用(轉(zhuǎn))
        public class Win32Hook
        {
        [DllImport("kernel32")]
        public static extern int GetCurrentThreadId();
        [DllImport( "user32",
        CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(
        HookType idHook,
        HOOKPROC lpfn,
        int hmod,
        int dwThreadId);
        public enum HookType
        {
        WH_KEYBOARD = 2
        }
        public delegate int HOOKPROC(int nCode, int wParam, int lParam);
        public void SetHook()
        {
        // set the keyboard hook
        SetWindowsHookEx(HookType.WH_KEYBOARD,
        new HOOKPROC(this.MyKeyboardProc),
        0,
        GetCurrentThreadId());
        }
        public int MyKeyboardProc(int nCode, int wParam, int lParam)
        {
        //在這里放置你的處理代碼 return 0;
        }
        }
        使用方法
        可以在Form的構(gòu)造函數(shù)里放入
        Win32Hook hook = new Win32Hook();
        hook.SetHook();
    主站蜘蛛池模板: 亚洲AV无码精品无码麻豆| jzzjzz免费观看大片免费| 国精无码欧精品亚洲一区| 性色av免费观看| 国产精品免费看久久久 | 一级毛片人与动免费观看| 亚洲毛片基地日韩毛片基地| 国产国拍亚洲精品福利| 午夜一区二区免费视频| 精品福利一区二区三区免费视频| 搡女人免费免费视频观看| 日韩免费码中文在线观看| 亚洲熟伦熟女专区hd高清| 亚洲日韩乱码中文无码蜜桃臀| 亚洲国产精品特色大片观看完整版| 免费午夜爽爽爽WWW视频十八禁| 成人一a毛片免费视频| 免费看污成人午夜网站| 中文字幕免费在线看线人| 三年片在线观看免费观看大全动漫 | 亚洲丝袜中文字幕| 亚洲精品第五页中文字幕| 亚洲av福利无码无一区二区 | 四虎影视在线看免费观看| 亚洲av无码专区青青草原| 亚洲性色AV日韩在线观看| 亚洲国产成人精品激情| 亚洲人6666成人观看| 亚洲国产成a人v在线| 亚洲国产成人精品无码区在线网站| 亚洲另类激情综合偷自拍| 国产亚洲成av人片在线观看| 国产亚洲成av片在线观看| 久久国产亚洲精品麻豆| 亚洲AV一宅男色影视| 亚洲成色999久久网站| 亚洲网址在线观看你懂的| 亚洲精品国产福利在线观看| 亚洲性69影院在线观看| 亚洲中文字幕无码久久| 亚洲成av人片天堂网无码】|