1. 程式人生 > >C# 在程式焦點之外捕捉按鍵操作(鍵盤鉤子的使用)

C# 在程式焦點之外捕捉按鍵操作(鍵盤鉤子的使用)

在程式中捕捉使用者的按鍵行為很容易,但是假如程式最小化了或者隱藏到系統托盤了,這時因為程式已經失去焦點了我們想捕捉按鍵行為就不是那麼容易了。怎麼辦呢?這就要使用鍵盤鉤子了。

關於鍵盤鉤子,下面這個網友描述的很詳盡,我就不班門弄斧了,轉載過來以備不時之需。原文:http://www.cnblogs.com/hocylan/archive/2008/01/14/1038390.html

概要

1 目的:完成簡單的監控和遮蔽

2 技術:鉤子(系統監控必須全域性鉤子)

3 步驟:

   A 安裝鉤子

   B 回撥函式

   C 處理函式

   D 普通業務處理

   ……

4 完成

下載源程式和執行程式

http://files.cnblogs.com/hocylan/KeyboardHook.rar

執行介面如下:

說明:

C++中實現該功能十分簡單,也有很多經典例子可以實現,在C#中確有很多問題會出現。

大概步驟

其實主要就是呼叫windows API
第一步
:安裝鉤子:SetWindowsHookEx(WH_Codes idHook, HookProc lpfn,IntPtr pInstance, int threadId);

第二步:回撥和處理CallNextHookEx(IntPtr pHookHandle, int nCode,Int32 wParam, IntPtr lParam);

第三步:完成普通的業務處理其它流程

將封裝的鉤子應用到系統中…….

private

void start_Click(object sender, EventArgs e)

        { hook_Main.InstallHook("1");}

        private void stop_Click(object sender, EventArgs e)

        {this.hook_Main.UnInstallHook();}

        private void stopkeyboard_Click(object sender, EventArgs e)

        { hook_Main.InstallHook("2"); }

第四步:拆卸鉤子

UnhookWindowsHookEx(IntPtr pHookHandle);

四 重要程式碼和解釋:

*封裝的hook類:

using System;

using System.Windows.Forms;

using System.Runtime.InteropServices; //必須引用

using System.Reflection; //必須引用

namespace KeyboardHook

{

    class Hocy_Hook

    {

        #region私有常量

         ///<summary>

         ///按鍵狀態陣列

         ///</summary>

         private readonly byte[] m_KeyState = new byte[ 256 ];

        private string flags;

        //flag=0 正常 flag=1 監控狀態 flag=2 遮蔽鍵盤//

         #endregion私有常量

         #region私有變數

         ///<summary>

         ///滑鼠鉤子控制代碼

         ///</summary>

         private IntPtr m_pMouseHook = IntPtr.Zero;

         ///<summary>

         ///鍵盤鉤子控制代碼

         ///</summary>

         private IntPtr m_pKeyboardHook = IntPtr.Zero;

         ///<summary>

         ///滑鼠鉤子委託例項

         ///</summary>

         ///<remarks>

         ///不要試圖省略此變數,否則將會導致

         ///啟用CallbackOnCollectedDelegate 託管除錯助手(MDA)。

         ///詳細請參見MSDN中關於CallbackOnCollectedDelegate 的描述

         ///</remarks>

         private HookProc m_MouseHookProcedure;

         ///<summary>

         ///鍵盤鉤子委託例項

         ///</summary>

         ///<remarks>

         ///不要試圖省略此變數,否則將會導致

         ///啟用CallbackOnCollectedDelegate 託管除錯助手(MDA)。

         ///詳細請參見MSDN中關於CallbackOnCollectedDelegate 的描述

         ///</remarks>

         private HookProc m_KeyboardHookProcedure;

        // 新增

        public event MouseEventHandler OnMouseActivity;

        private const byte VK_SHIFT = 0x10 ;

        private const byte VK_CAPITAL = 0x14;

        private const byte VK_NUMLOCK = 0x90;

         #endregion私有變數

         #region事件定義

         ///<summary>

         ///滑鼠更新事件

         ///</summary>

         ///<remarks>當滑鼠移動或者滾輪滾動時觸發</remarks>

         public event MouseUpdateEventHandler OnMouseUpdate;

         ///<summary>

         ///按鍵按下事件

         ///</summary>

         public event KeyEventHandler OnKeyDown;

         ///<summary>

         ///按鍵按下並釋放事件

         ///</summary>

         public event KeyPressEventHandler OnKeyPress;

         ///<summary>

         ///按鍵釋放事件

         ///</summary>

         public event KeyEventHandler OnKeyUp;

         #endregion事件定義

         #region私有方法

         ///<summary>

         ///滑鼠鉤子處理函式

         ///</summary>

         ///<param name="nCode"></param>

         ///<param name="wParam"></param>

         ///<param name="lParam"></param>

         ///<returns>滑鼠鉤子處理函式</returns>

         private int MouseHookProc( int nCode, Int32 wParam, IntPtr lParam )

         {

 if ((nCode >= 0) && (OnMouseActivity != null))

            {

                //Marshall the data from callback.

                MouseHookStruct mouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

                //detect button clicked

                MouseButtons button = MouseButtons.None;

                short mouseDelta = 0;

                switch (wParam)

                {

                    case (int)WM_MOUSE.WM_LBUTTONDOWN:

                        //case WM_LBUTTONUP:

                        //case WM_LBUTTONDBLCLK:

                        button = MouseButtons.Left;

                        break;

                    case (int)WM_MOUSE.WM_RBUTTONDOWN:

                        //case WM_RBUTTONUP:

                        //case WM_RBUTTONDBLCLK:

                        button = MouseButtons.Right;

                        break;

                    case (int)WM_MOUSE.WM_MOUSEWHEEL:

                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.

                        //One wheel click is defined as WHEEL_DELTA, which is 120.

                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value

                        mouseDelta = (short)((mouseHookStruct.MouseData>> 16) & 0xffff);

                        //TODO: X BUTTONS (I havent them so was unable to test)

                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,

                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,

                        //and the low-order word is reserved. This value can be one or more of the following values.

                        //Otherwise, mouseData is not used.

                        break;

                }

                //double clicks

                int clickCount = 0;

                if (button != MouseButtons.None)

                    if (wParam == (int)WM_MOUSE.WM_LBUTTONDBLCLK || wParam == (int)WM_MOUSE.WM_RBUTTONDBLCLK) clickCount = 2;

                    else clickCount = 1;

                //generate event

                MouseEventArgs e = new MouseEventArgs(

                                                   button,

                                                   clickCount,

                                                   mouseHookStruct.Point.X,

                                                   mouseHookStruct.Point.Y,

                                                   mouseDelta);

                //raise it

                OnMouseActivity(this, e);

            } 

            //*

              return Win32API.CallNextHookEx( this.m_pMouseHook, nCode, wParam, lParam );

         }

         ///<summary>

         ///鍵盤鉤子處理函式

         ///</summary>

         ///<param name="nCode"></param>

         ///<param name="wParam"></param>

         ///<param name="lParam"></param>

         ///<returns></returns>

         ///<remarks></remarks>

         private int KeyboardHookProc( int nCode, Int32 wParam, IntPtr lParam )

         {

            switch (flags)

            {

                case "2":

                    return 1;

                    break;

                case "1":

                    break;

            }

            bool handled = false;

            //it was ok and someone listens to events

            if ((nCode >= 0) && (this.OnKeyDown != null || this.OnKeyUp!= null || this.OnKeyPress!= null))

            {

                //read structure KeyboardHookStruct at lParam

                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));

                //raise KeyDown

                if (this.OnKeyDown != null && (wParam == (int)WM_KEYBOARD.WM_KEYDOWN || wParam == (int)WM_KEYBOARD.WM_SYSKEYDOWN))

                {

                    Keys keyData = (Keys)MyKeyboardHookStruct.VKCode;

                    KeyEventArgs e = new KeyEventArgs(keyData);

                   this.OnKeyDown(this, e);

                    handled = handled || e.Handled;

                }

                // raise KeyPress

                    if (this.OnKeyPress != null && wParam == (int)WM_KEYBOARD.WM_KEYDOWN)

                    {

                        bool isDownShift, isDownCapslock;

                        try

                        {

                             isDownShift = ((Win32API.GetKeyStates(VK_SHIFT) & 0x80) == 0x80 ? true : false);

                            isDownCapslock = (Win32API.GetKeyStates(VK_CAPITAL) != 0 ? true : false);

                        }

                        catch

                        {

                            isDownCapslock = false;

                            isDownShift= false;

                        }

                        byte[] keyState = new byte[256];

                       Win32API.GetKeyboardState(keyState);

                        byte[] inBuffer = new byte[2];

                        if (Win32API.ToAscii(MyKeyboardHookStruct.VKCode,

                                  MyKeyboardHookStruct.ScanCode,

                                  keyState,

                                  inBuffer,

                                  MyKeyboardHookStruct.Flags) == 1)

                        {

                            char key = (char)inBuffer[0];

                            if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);

                            KeyPressEventArgs e = new KeyPressEventArgs(key);

                            this.OnKeyPress(this, e);

                            handled = handled || e.Handled;

                        }

                    }

                // raise KeyUp

                if (this.OnKeyUp != null && (wParam == (int)WM_KEYBOARD.WM_KEYUP || wParam == (int)WM_KEYBOARD.WM_SYSKEYUP))

                {

                    Keys keyData = (Keys)MyKeyboardHookStruct.VKCode;

                    KeyEventArgs e = new KeyEventArgs(keyData);

                    this.OnKeyUp(this, e);

                    handled = handled || e.Handled;

                }

            }

            //if event handled in application do not handoff to other listeners

            if (handled)

                return 1;

            else

                return Win32API.CallNextHookEx(this.m_pKeyboardHook, nCode, wParam, lParam);

        }

         #endregion私有方法

         #region公共方法

         ///<summary>

         ///安裝鉤子

         ///</summary>

         ///<returns></returns>

         public bool InstallHook(string flagsinfo)

         {

            this.flags = flagsinfo;

IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);

//pInstance = (IntPtr)4194304;

          //注意:很多時候得到的pInstanc無法安裝鉤子,請檢查值是否為4194304,在應用程式中可以直接取得pinstance的

           // IntPtr pInstanc2 = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly());

           // Assembly.GetExecutingAssembly().GetModules()[0]

              //安裝滑鼠鉤子

              if ( this.m_pMouseHook == IntPtr.Zero )

              {

                   this.m_MouseHookProcedure = new HookProc( this.MouseHookProc );

                   this.m_pMouseHook = Win32API.SetWindowsHookEx( WH_Codes.WH_MOUSE_LL,this.m_MouseHookProcedure, pInstance, 0 );

// WH_Codes.WH_MOUSE_LL為全域性鉤子即系統鉤子,否則應該為WH_Codes.WH_KEYBOARD,即普通鉤子

                   if ( this.m_pMouseHook == IntPtr.Zero )

                   {

                       this.UnInstallHook();

                       return false;

                   }

              }

              if ( this.m_pKeyboardHook == IntPtr.Zero ) //安裝鍵盤鉤子

              {

                   this.m_KeyboardHookProcedure = new HookProc( this.KeyboardHookProc );

                  // WH_Codes.WH_KEYBOARD_LL為全域性鉤子即系統鉤子,否則應該為WH_Codes.WH_KEYBOARD,即普通鉤子

                   this.m_pKeyboardHook = Win32API.SetWindowsHookEx( WH_Codes.WH_KEYBOARD_LL,this.m_KeyboardHookProcedure, pInstance, 0 );

                   if ( this.m_pKeyboardHook == IntPtr.Zero )

                   {

                       this.UnInstallHook();

                       return false;

                   }

              }

              return true;

         }

         ///<summary>

         ///解除安裝鉤子

         ///</summary>

         ///<returns></returns>

        

相關推薦

C# 在程式焦點之外捕捉按鍵操作鍵盤鉤子的使用

在程式中捕捉使用者的按鍵行為很容易,但是假如程式最小化了或者隱藏到系統托盤了,這時因為程式已經失去焦點了我們想捕捉按鍵行為就不是那麼容易了。怎麼辦呢?這就要使用鍵盤鉤子了。 關於鍵盤鉤子,下面這個網友描述的很詳盡,我就不班門弄斧了,轉載過來以備不時之需。原文:http://

C語言_棧的基本操作順序棧

##本片部落格主要是順序棧的基本操作,包含以下內容: 初始化 入棧 出棧 判空 判滿 返回棧頂元素(棧頂元素不出棧) 返回棧頂元素(棧頂元素出棧) ###順序棧的初始化: 初始化順序棧時只需要讓棧頂等零 void InitStack (Stack *p) //初始化

CLR via C# 讀書筆記-27.計算限制的異步操作上篇

top oid 輔助線 var 思考 read 運行 簡單例子 class 前言 學習這件事情是一個習慣,不能停。。。另外這篇已經看過兩個月過去,但覺得有些事情不總結跟沒做沒啥區別,遂記下此文 1.CLR線程池基礎 2.ThreadPool的簡單使用練習 3.執行上下文 4

C#中對sqlserver進行增刪改查操作簡單易懂

uid 數據連接 net cti ade 密碼 logs where Go 1、添加引用using System.Data;using System.Data.SqlData;2、建立於數據庫的連接,建議將它做成一個方法,方便多次利用。string sqlconnectio

C WinForm 開發Windows7多點觸控Multi-Touch應用程式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

C語言 線性表的操作~未完

#include <stdio.h> #include <malloc.h> typedef struct{ int *elem; //基地址 int length; int listsize; }Seqlist;//定義Seq這個新的資料

微信小程式向左滑動刪除操作類仿微信、QQ

上一個小程式的專案裡面做過這個功能,當時沒有記錄下來,今天特意做了一個小的demo放在了github上面,下次在開發中遇到的話就可以直接拿下來程式碼複用了。效果很簡單,類似於微信扣扣刪除聊天欄的效果,想左滑動,出現刪除按鈕,點選即可刪除。 github地址:https://github

C# EMGU 3.4.1學習筆記十一示例程式:仿射變換

本示例是《OpenCV3程式設計入門》中7.4.5中的示例程式的C# + EMGU 3.4.1版,演示了以WarpAffine和GetRotationMatrix2D函式為核心的對影象進行仿射變換的操作。 using System; using System.Collect

C# EMGU 3.4.1學習筆記十二示例程式:直方圖均衡化彩色影象

本示例是《OpenCV3程式設計入門》中7.5.3中的示例程式的C# + EMGU 3.4.1版,演示瞭如何用EqualizeHist()函式進行影象的直方圖均衡化。 原書程式碼僅演示了對灰度影象的直方圖均衡化,對此我做了一些改變,從而可對彩色影象進行直方圖均衡化。 彩色

C++ 異常捕捉與處理try...catch...

首先舉一個異常處理的例子: string str = "0123456789"; char ch1 = str[100];    //陣列越界,但是不提醒,程式執行立即崩潰 cout << ch1 << endl;    &n

C#Winform關於對xml檔案的一系列操作持續更新

// 讀取xml檔案到DataTable string filepath = Application.StartupPath + @"\Previous Competitions

C++11中的原子操作atomic operation

所謂的原子操作,取的就是“原子是最小的、不可分割的最小個體”的意義,它表示在多個執行緒訪問同一個全域性資源的時候,能夠確保所有其他的執行緒都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的執行緒對這個資源進行訪問。這有點類似互斥物件對共享資源的訪問的保護,但是原子操作更加接

C#中對資料庫的基本操作增刪改以及呼叫儲存過程

因為最近在寫web API的時候需要對資料庫操作,所以要用到ADO.NET,因為之前沒有接觸過.NET所以也是一邊上網查資料看C#書一邊寫,現在對這塊基礎的部分已經掌握了,現在寫下來只是想對自己前段時間的學習做個簡單的總結,也便於自己以後查閱(網上有很多類似的資源,大家可以

c# winform 關於DataGridView的一些操作很全,絕對夠用

設定欄位名  設定欄位值  設定單元格表示 Error圖示  設定當前單元格  取得當前單元格內容  取得當前單元格的列 Index  取得當前單元格的行 Index  向下一行 

c++實現鏈棧的基本操作附帶main函式 可編譯執行

資料結構老師佈置了鏈棧的基本操作,讓我們儘量嘗試用class實現,然後我在網上參考了一部分,自己寫了一個,有不足之處懇請大家指出 /*  *  檔名:鏈棧.c  *    鏈棧的實現  *    版本:2.0  *    時間:2016.11.4  *    作者:Wan

C++ 程式設計師買房子的故事九度OJ 1158

 題目描述:     某程式設計師開始工作,年薪N萬,他希望在中關村公館買一套60平米的房子,現在價格是200萬,假設房子價格以每年百分之K增長,並且該程式設計師未來年薪不變,且不吃不喝,不用交稅,每年所得N萬全都積攢起來,問第幾年能夠買下這套房子(第一年房價200萬

c++中字元陣列操作char陣列

問題:學習C語言時,用字串的函式例如stpcpy()、strcat()、strcmp()等,要包含標頭檔案string.h 學習C++後,C++有字串的標準類string,string類也有很多方法,用string類時要用到string.h標頭檔案。 我現在看vc的書

C++ 目錄檔案操作持續更新

判斷目錄是否存在,存在便刪除: #include<sstream> #include<unistd.h> void DeleteIfExist(char* path)

Qt程式crash資訊的捕捉與跟蹤qt-mingw

在用qt編寫程式時經常會遇到崩潰問題,如果抓取不到crash堆疊資訊就會對崩潰問題束手無策,只能對其進行復現,推斷。 目錄 步驟1: 步驟2: 步驟3: 網友評論: 一般解決crash問題時有如下步驟: 從軟體發行版本能跟獲得debug資

使用C#對Excel進行讀寫操作NPOI以及使用EF對Mysql進行CURD

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq;